Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / xfa_test / pdf / fading_controls.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "pdf/fading_controls.h"
6
7 #include "base/logging.h"
8 #include "base/stl_util.h"
9 #include "pdf/draw_utils.h"
10 #include "pdf/resource_consts.h"
11 #include "ppapi/cpp/input_event.h"
12
13 namespace chrome_pdf {
14
15 const uint32 kFadingAlphaShift = 64;
16 const uint32 kSplashFadingAlphaShift = 16;
17
18 FadingControls::FadingControls()
19     : state_(NONE), current_transparency_(kOpaqueAlpha), fading_timer_id_(0),
20       current_capture_control_(kInvalidControlId),
21       fading_timeout_(kFadingTimeoutMs), alpha_shift_(kFadingAlphaShift),
22       splash_(false), splash_timeout_(0) {
23 }
24
25 FadingControls::~FadingControls() {
26   STLDeleteElements(&controls_);
27 }
28
29 bool FadingControls::CreateFadingControls(
30     uint32 id, const pp::Rect& rc, bool visible,
31     Control::Owner* owner, uint8 transparency) {
32   current_transparency_ = transparency;
33   return Control::Create(id, rc, visible, owner);
34 }
35
36 void FadingControls::Paint(pp::ImageData* image_data, const pp::Rect& rc) {
37   // When this control is set to invisible the individual controls are not.
38   // So we need to check for visible() here.
39   if (!visible())
40     return;
41
42   std::list<Control*>::iterator iter;
43   for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
44     (*iter)->Paint(image_data, rc);
45   }
46 }
47
48 bool FadingControls::HandleEvent(const pp::InputEvent& event) {
49   if (!visible())
50     return false;
51
52   pp::MouseInputEvent mouse_event(event);
53   if (mouse_event.is_null())
54     return NotifyControls(event);
55
56   pp::Point pt = mouse_event.GetPosition();
57
58   bool is_mouse_click =
59       mouse_event.GetType() == PP_INPUTEVENT_TYPE_MOUSEDOWN ||
60       mouse_event.GetType() == PP_INPUTEVENT_TYPE_MOUSEUP;
61
62   if (rect().Contains(pt)) {
63     CancelSplashMode();
64     FadeIn();
65
66     // Eat mouse click if are invisible or just fading in.
67     // That prevents accidental clicks on the controls for touch devices.
68     bool eat_mouse_click =
69         (state_ == FADING_IN || current_transparency_ == kTransparentAlpha);
70     if (eat_mouse_click && is_mouse_click &&
71         mouse_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT)
72       return true;  // Eat this event here.
73   }
74
75   if ((!rect().Contains(pt)) ||
76       event.GetType() == PP_INPUTEVENT_TYPE_MOUSELEAVE) {
77     if (!splash_)
78       FadeOut();
79     pp::MouseInputEvent event_leave(pp::MouseInputEvent(
80         owner()->GetInstance(),
81         PP_INPUTEVENT_TYPE_MOUSELEAVE,
82         event.GetTimeStamp(),
83         event.GetModifiers(),
84         mouse_event.GetButton(),
85         mouse_event.GetPosition(),
86         mouse_event.GetClickCount(),
87         mouse_event.GetMovement()));
88     return NotifyControls(event_leave);
89   }
90
91   return NotifyControls(event);
92 }
93
94 void FadingControls::OnTimerFired(uint32 timer_id) {
95   if (timer_id == fading_timer_id_) {
96     int32 current_alpha = static_cast<int32>(current_transparency_);
97     if (state_ == FADING_IN)
98       current_alpha += alpha_shift_;
99     else if (state_ == FADING_OUT)
100       current_alpha -= alpha_shift_;
101
102     if (current_alpha >= kOpaqueAlpha) {
103       state_ = NONE;
104       current_alpha = kOpaqueAlpha;
105     } else if (current_alpha <= kTransparentAlpha) {
106       state_ = NONE;
107       current_alpha = kTransparentAlpha;
108     }
109     current_transparency_ = static_cast<uint8>(current_alpha);
110
111     // Invalidate controls with new alpha transparency.
112     std::list<Control*>::iterator iter;
113     for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
114       // We are going to invalidate the whole FadingControls area, to
115       // allow simultaneous drawing.
116       (*iter)->AdjustTransparency(current_transparency_, false);
117     }
118     owner()->Invalidate(id(), GetControlsRect());
119
120     if (state_ != NONE)  // Fading still in progress.
121       fading_timer_id_ = owner()->ScheduleTimer(id(), fading_timeout_);
122     else
123       OnFadingComplete();
124   } else {
125     // Dispatch timer to controls.
126     std::list<Control*>::iterator iter;
127     for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
128       (*iter)->OnTimerFired(timer_id);
129     }
130   }
131 }
132
133 void FadingControls::EventCaptureReleased() {
134   if (current_capture_control_ != kInvalidControlId) {
135     // Remove previous catpure.
136     Control* ctrl = GetControl(current_capture_control_);
137     if (ctrl)
138       ctrl->EventCaptureReleased();
139   }
140 }
141
142 void FadingControls::MoveBy(const pp::Point& offset, bool invalidate) {
143   std::list<Control*>::iterator iter;
144   for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
145     // We invalidate entire FadingControl later if needed.
146     (*iter)->MoveBy(offset, false);
147   }
148   Control::MoveBy(offset, invalidate);
149 }
150
151 void FadingControls::OnEvent(uint32 control_id, uint32 event_id, void* data) {
152   owner()->OnEvent(control_id, event_id, data);
153 }
154
155 void FadingControls::Invalidate(uint32 control_id, const pp::Rect& rc) {
156   owner()->Invalidate(control_id, rc);
157 }
158
159 uint32 FadingControls::ScheduleTimer(uint32 control_id, uint32 timeout_ms) {
160   // TODO(gene): implement timer routine properly.
161   NOTIMPLEMENTED();
162   //owner()->ScheduleTimer(control_id);
163   return 0;
164 }
165
166 void FadingControls::SetEventCapture(uint32 control_id, bool set_capture) {
167   if (control_id == current_capture_control_) {
168     if (!set_capture)  // Remove event capture.
169       current_capture_control_ = kInvalidControlId;
170   } else {
171     EventCaptureReleased();
172     current_capture_control_ = control_id;
173   }
174 }
175
176 void FadingControls::SetCursor(uint32 control_id,
177                                PP_CursorType_Dev cursor_type) {
178   owner()->SetCursor(control_id, cursor_type);
179 }
180
181 pp::Instance* FadingControls::GetInstance() {
182   return owner()->GetInstance();
183 }
184
185 bool FadingControls::AddControl(Control* control) {
186   DCHECK(control);
187   if (control->owner() != this)
188     return false;
189   if (!rect().Contains(control->rect()))
190     return false;
191
192   control->AdjustTransparency(current_transparency_, false);
193   controls_.push_back(control);
194   return true;
195 }
196
197 void FadingControls::RemoveControl(uint32 control_id) {
198   if (current_capture_control_ == control_id) {
199     current_capture_control_ = kInvalidControlId;
200   }
201   std::list<Control*>::iterator iter;
202   for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
203     if ((*iter)->id() == control_id) {
204       delete (*iter);
205       controls_.erase(iter);
206       break;
207     }
208   }
209 }
210
211 Control* FadingControls::GetControl(uint32 id) {
212   std::list<Control*>::iterator iter;
213   for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
214     if ((*iter)->id() == id)
215       return *iter;
216   }
217   return NULL;
218 }
219
220 pp::Rect FadingControls::GetControlsRect() {
221   pp::Rect rc;
222   std::list<Control*>::iterator iter;
223   for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
224     rc = rc.Union((*iter)->rect());
225   }
226   return rc;
227 }
228
229 bool FadingControls::ExpandLeft(int offset) {
230   pp::Rect rc = rect();
231   rc.set_width(rc.width() + offset);
232   rc.set_x(rc.x() - offset);
233   if (!rc.Contains(GetControlsRect()))
234     return false;
235   // No need to invalidate since we are expanding triggering area only.
236   SetRect(rc, false);
237   return true;
238 }
239
240 void FadingControls::Splash(uint32 time_ms) {
241   splash_ = true;
242   splash_timeout_ = time_ms;
243   alpha_shift_ = kSplashFadingAlphaShift;
244   FadeIn();
245 }
246
247 bool FadingControls::NotifyControls(const pp::InputEvent& event) {
248   // First pass event to a control that current capture is set to.
249   Control* ctrl = GetControl(current_capture_control_);
250   if (ctrl) {
251     if (ctrl->HandleEvent(event))
252       return true;
253   }
254
255   std::list<Control*>::iterator iter;
256   for (iter = controls_.begin(); iter != controls_.end(); ++iter) {
257     // Now pass event to all control except control with capture,
258     // since we already passed to it above.
259     if ((*iter) != ctrl && (*iter)->HandleEvent(event))
260       return true;
261   }
262   return false;
263 }
264
265 void FadingControls::FadeIn() {
266   bool already_visible =
267       (state_ == NONE && current_transparency_ == kOpaqueAlpha);
268   if (state_ != FADING_IN && !already_visible) {
269     state_ = FADING_IN;
270     fading_timer_id_ = owner()->ScheduleTimer(id(), fading_timeout_);
271   }
272   if (already_visible)
273     OnFadingComplete();
274 }
275
276 void FadingControls::FadeOut() {
277   bool already_invisible =
278       (state_ == NONE && current_transparency_ == kTransparentAlpha);
279   if (state_ != FADING_OUT && !already_invisible) {
280     state_ = FADING_OUT;
281     fading_timer_id_ = owner()->ScheduleTimer(id(), fading_timeout_);
282   }
283   if (already_invisible)
284     OnFadingComplete();
285 }
286
287 void FadingControls::OnFadingComplete() {
288   DCHECK(current_transparency_ == kOpaqueAlpha ||
289       current_transparency_ == kTransparentAlpha);
290   // In the splash mode following states are possible:
291   // Fade-in complete: splash_==true, splash_timeout_ != 0
292   //   We need to schedule timer for splash_timeout_.
293   // Splash timeout complete: splash_==true, splash_timeout_ == 0
294   //   We need to fade out still using splash settings.
295   // Fade-out complete: current_transparency_ == kTransparentAlpha
296   //   We need to cancel splash mode and go back to normal settings.
297   if (splash_) {
298     if (current_transparency_ == kOpaqueAlpha) {
299       if (splash_timeout_) {
300         fading_timer_id_ = owner()->ScheduleTimer(id(), splash_timeout_);
301         splash_timeout_ = 0;
302       } else {
303         FadeOut();
304       }
305     } else {
306       CancelSplashMode();
307     }
308   }
309 }
310
311 void FadingControls::CancelSplashMode() {
312   splash_ = false;
313   alpha_shift_ = kFadingAlphaShift;
314 }
315
316 }  // namespace chrome_pdf