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 317