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
FadingControls()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
~FadingControls()25 FadingControls::~FadingControls() {
26 STLDeleteElements(&controls_);
27 }
28
CreateFadingControls(uint32 id,const pp::Rect & rc,bool visible,Control::Owner * owner,uint8 transparency)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
Paint(pp::ImageData * image_data,const pp::Rect & rc)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
HandleEvent(const pp::InputEvent & event)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
OnTimerFired(uint32 timer_id)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
EventCaptureReleased()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
MoveBy(const pp::Point & offset,bool invalidate)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
OnEvent(uint32 control_id,uint32 event_id,void * data)151 void FadingControls::OnEvent(uint32 control_id, uint32 event_id, void* data) {
152 owner()->OnEvent(control_id, event_id, data);
153 }
154
Invalidate(uint32 control_id,const pp::Rect & rc)155 void FadingControls::Invalidate(uint32 control_id, const pp::Rect& rc) {
156 owner()->Invalidate(control_id, rc);
157 }
158
ScheduleTimer(uint32 control_id,uint32 timeout_ms)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
SetEventCapture(uint32 control_id,bool set_capture)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
SetCursor(uint32 control_id,PP_CursorType_Dev cursor_type)176 void FadingControls::SetCursor(uint32 control_id,
177 PP_CursorType_Dev cursor_type) {
178 owner()->SetCursor(control_id, cursor_type);
179 }
180
GetInstance()181 pp::Instance* FadingControls::GetInstance() {
182 return owner()->GetInstance();
183 }
184
AddControl(Control * control)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
RemoveControl(uint32 control_id)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
GetControl(uint32 id)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
GetControlsRect()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
ExpandLeft(int offset)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
Splash(uint32 time_ms)240 void FadingControls::Splash(uint32 time_ms) {
241 splash_ = true;
242 splash_timeout_ = time_ms;
243 alpha_shift_ = kSplashFadingAlphaShift;
244 FadeIn();
245 }
246
NotifyControls(const pp::InputEvent & event)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
FadeIn()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
FadeOut()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
OnFadingComplete()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
CancelSplashMode()311 void FadingControls::CancelSplashMode() {
312 splash_ = false;
313 alpha_shift_ = kFadingAlphaShift;
314 }
315
316 } // namespace chrome_pdf
317