summaryrefslogtreecommitdiffstats
path: root/pdf/fading_controls.cc
blob: 8a9fd895102be4df8c040ea685638f258ca9db5c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "pdf/fading_controls.h"

#include "base/logging.h"
#include "base/stl_util.h"
#include "pdf/draw_utils.h"
#include "pdf/resource_consts.h"
#include "ppapi/cpp/input_event.h"

namespace chrome_pdf {

const uint32 kFadingAlphaShift = 64;
const uint32 kSplashFadingAlphaShift = 16;

FadingControls::FadingControls()
    : state_(NONE), current_transparency_(kOpaqueAlpha), fading_timer_id_(0),
      current_capture_control_(kInvalidControlId),
      fading_timeout_(kFadingTimeoutMs), alpha_shift_(kFadingAlphaShift),
      splash_(false), splash_timeout_(0) {
}

FadingControls::~FadingControls() {
  STLDeleteElements(&controls_);
}

bool FadingControls::CreateFadingControls(
    uint32 id, const pp::Rect& rc, bool visible,
    Control::Owner* owner, uint8 transparency) {
  current_transparency_ = transparency;
  return Control::Create(id, rc, visible, owner);
}

void FadingControls::Paint(pp::ImageData* image_data, const pp::Rect& rc) {
  // When this control is set to invisible the individual controls are not.
  // So we need to check for visible() here.
  if (!visible())
    return;

  std::list<Control*>::iterator iter;
  for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
    (*iter)->Paint(image_data, rc);
  }
}

bool FadingControls::HandleEvent(const pp::InputEvent& event) {
  if (!visible())
    return false;

  pp::MouseInputEvent mouse_event(event);
  if (mouse_event.is_null())
    return NotifyControls(event);

  pp::Point pt = mouse_event.GetPosition();

  bool is_mouse_click =
      mouse_event.GetType() == PP_INPUTEVENT_TYPE_MOUSEDOWN ||
      mouse_event.GetType() == PP_INPUTEVENT_TYPE_MOUSEUP;

  if (rect().Contains(pt)) {
    CancelSplashMode();
    FadeIn();

    // Eat mouse click if are invisible or just fading in.
    // That prevents accidental clicks on the controls for touch devices.
    bool eat_mouse_click =
        (state_ == FADING_IN || current_transparency_ == kTransparentAlpha);
    if (eat_mouse_click && is_mouse_click &&
        mouse_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT)
      return true;  // Eat this event here.
  }

  if ((!rect().Contains(pt)) ||
      event.GetType() == PP_INPUTEVENT_TYPE_MOUSELEAVE) {
    if (!splash_)
      FadeOut();
    pp::MouseInputEvent event_leave(pp::MouseInputEvent(
        owner()->GetInstance(),
        PP_INPUTEVENT_TYPE_MOUSELEAVE,
        event.GetTimeStamp(),
        event.GetModifiers(),
        mouse_event.GetButton(),
        mouse_event.GetPosition(),
        mouse_event.GetClickCount(),
        mouse_event.GetMovement()));
    return NotifyControls(event_leave);
  }

  return NotifyControls(event);
}

void FadingControls::OnTimerFired(uint32 timer_id) {
  if (timer_id == fading_timer_id_) {
    int32 current_alpha = static_cast<int32>(current_transparency_);
    if (state_ == FADING_IN)
      current_alpha += alpha_shift_;
    else if (state_ == FADING_OUT)
      current_alpha -= alpha_shift_;

    if (current_alpha >= kOpaqueAlpha) {
      state_ = NONE;
      current_alpha = kOpaqueAlpha;
    } else if (current_alpha <= kTransparentAlpha) {
      state_ = NONE;
      current_alpha = kTransparentAlpha;
    }
    current_transparency_ = static_cast<uint8>(current_alpha);

    // Invalidate controls with new alpha transparency.
    std::list<Control*>::iterator iter;
    for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
      // We are going to invalidate the whole FadingControls area, to
      // allow simultaneous drawing.
      (*iter)->AdjustTransparency(current_transparency_, false);
    }
    owner()->Invalidate(id(), GetControlsRect());

    if (state_ != NONE)  // Fading still in progress.
      fading_timer_id_ = owner()->ScheduleTimer(id(), fading_timeout_);
    else
      OnFadingComplete();
  } else {
    // Dispatch timer to controls.
    std::list<Control*>::iterator iter;
    for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
      (*iter)->OnTimerFired(timer_id);
    }
  }
}

void FadingControls::EventCaptureReleased() {
  if (current_capture_control_ != kInvalidControlId) {
    // Remove previous catpure.
    Control* ctrl = GetControl(current_capture_control_);
    if (ctrl)
      ctrl->EventCaptureReleased();
  }
}

void FadingControls::MoveBy(const pp::Point& offset, bool invalidate) {
  std::list<Control*>::iterator iter;
  for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
    // We invalidate entire FadingControl later if needed.
    (*iter)->MoveBy(offset, false);
  }
  Control::MoveBy(offset, invalidate);
}

void FadingControls::OnEvent(uint32 control_id, uint32 event_id, void* data) {
  owner()->OnEvent(control_id, event_id, data);
}

void FadingControls::Invalidate(uint32 control_id, const pp::Rect& rc) {
  owner()->Invalidate(control_id, rc);
}

uint32 FadingControls::ScheduleTimer(uint32 control_id, uint32 timeout_ms) {
  // TODO(gene): implement timer routine properly.
  NOTIMPLEMENTED();
  //owner()->ScheduleTimer(control_id);
  return 0;
}

void FadingControls::SetEventCapture(uint32 control_id, bool set_capture) {
  if (control_id == current_capture_control_) {
    if (!set_capture)  // Remove event capture.
      current_capture_control_ = kInvalidControlId;
  } else {
    EventCaptureReleased();
    current_capture_control_ = control_id;
  }
}

void FadingControls::SetCursor(uint32 control_id,
                               PP_CursorType_Dev cursor_type) {
  owner()->SetCursor(control_id, cursor_type);
}

pp::Instance* FadingControls::GetInstance() {
  return owner()->GetInstance();
}

bool FadingControls::AddControl(Control* control) {
  DCHECK(control);
  if (control->owner() != this)
    return false;
  if (!rect().Contains(control->rect()))
    return false;

  control->AdjustTransparency(current_transparency_, false);
  controls_.push_back(control);
  return true;
}

void FadingControls::RemoveControl(uint32 control_id) {
  if (current_capture_control_ == control_id) {
    current_capture_control_ = kInvalidControlId;
  }
  std::list<Control*>::iterator iter;
  for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
    if ((*iter)->id() == control_id) {
      delete (*iter);
      controls_.erase(iter);
      break;
    }
  }
}

Control* FadingControls::GetControl(uint32 id) {
  std::list<Control*>::iterator iter;
  for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
    if ((*iter)->id() == id)
      return *iter;
  }
  return NULL;
}

pp::Rect FadingControls::GetControlsRect() {
  pp::Rect rc;
  std::list<Control*>::iterator iter;
  for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
    rc = rc.Union((*iter)->rect());
  }
  return rc;
}

bool FadingControls::ExpandLeft(int offset) {
  pp::Rect rc = rect();
  rc.set_width(rc.width() + offset);
  rc.set_x(rc.x() - offset);
  if (!rc.Contains(GetControlsRect()))
    return false;
  // No need to invalidate since we are expanding triggering area only.
  SetRect(rc, false);
  return true;
}

void FadingControls::Splash(uint32 time_ms) {
  splash_ = true;
  splash_timeout_ = time_ms;
  alpha_shift_ = kSplashFadingAlphaShift;
  FadeIn();
}

bool FadingControls::NotifyControls(const pp::InputEvent& event) {
  // First pass event to a control that current capture is set to.
  Control* ctrl = GetControl(current_capture_control_);
  if (ctrl) {
    if (ctrl->HandleEvent(event))
      return true;
  }

  std::list<Control*>::iterator iter;
  for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
    // Now pass event to all control except control with capture,
    // since we already passed to it above.
    if ((*iter) != ctrl && (*iter)->HandleEvent(event))
      return true;
  }
  return false;
}

void FadingControls::FadeIn() {
  bool already_visible =
      (state_ == NONE && current_transparency_ == kOpaqueAlpha);
  if (state_ != FADING_IN && !already_visible) {
    state_ = FADING_IN;
    fading_timer_id_ = owner()->ScheduleTimer(id(), fading_timeout_);
  }
  if (already_visible)
    OnFadingComplete();
}

void FadingControls::FadeOut() {
  bool already_invisible =
      (state_ == NONE && current_transparency_ == kTransparentAlpha);
  if (state_ != FADING_OUT && !already_invisible) {
    state_ = FADING_OUT;
    fading_timer_id_ = owner()->ScheduleTimer(id(), fading_timeout_);
  }
  if (already_invisible)
    OnFadingComplete();
}

void FadingControls::OnFadingComplete() {
  DCHECK(current_transparency_ == kOpaqueAlpha ||
      current_transparency_ == kTransparentAlpha);
  // In the splash mode following states are possible:
  // Fade-in complete: splash_==true, splash_timeout_ != 0
  //   We need to schedule timer for splash_timeout_.
  // Splash timeout complete: splash_==true, splash_timeout_ == 0
  //   We need to fade out still using splash settings.
  // Fade-out complete: current_transparency_ == kTransparentAlpha
  //   We need to cancel splash mode and go back to normal settings.
  if (splash_) {
    if (current_transparency_ == kOpaqueAlpha) {
      if (splash_timeout_) {
        fading_timer_id_ = owner()->ScheduleTimer(id(), splash_timeout_);
        splash_timeout_ = 0;
      } else {
        FadeOut();
      }
    } else {
      CancelSplashMode();
    }
  }
}

void FadingControls::CancelSplashMode() {
  splash_ = false;
  alpha_shift_ = kFadingAlphaShift;
}

}  // namespace chrome_pdf