| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2006, 2008, 2010 Apple Inc. All rights reserved. | |
| 3 * Copyright (C) 2010 Google Inc. All rights reserved. | |
| 4 * | |
| 5 * Redistribution and use in source and binary forms, with or without | |
| 6 * modification, are permitted provided that the following conditions | |
| 7 * are met: | |
| 8 * 1. Redistributions of source code must retain the above copyright | |
| 9 * notice, this list of conditions and the following disclaimer. | |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | |
| 11 * notice, this list of conditions and the following disclaimer in the | |
| 12 * documentation and/or other materials provided with the distribution. | |
| 13 * | |
| 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY | |
| 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
| 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR | |
| 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
| 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
| 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
| 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 25 */ | |
| 26 | |
| 27 #include "core/html/shadow/SpinButtonElement.h" | |
| 28 | |
| 29 #include "core/HTMLNames.h" | |
| 30 #include "core/dom/TaskRunnerHelper.h" | |
| 31 #include "core/events/MouseEvent.h" | |
| 32 #include "core/events/WheelEvent.h" | |
| 33 #include "core/frame/LocalFrame.h" | |
| 34 #include "core/html/shadow/ShadowElementNames.h" | |
| 35 #include "core/input/EventHandler.h" | |
| 36 #include "core/layout/LayoutBox.h" | |
| 37 #include "core/page/ChromeClient.h" | |
| 38 #include "core/page/Page.h" | |
| 39 #include "platform/scroll/ScrollbarTheme.h" | |
| 40 | |
| 41 namespace blink { | |
| 42 | |
| 43 using namespace HTMLNames; | |
| 44 | |
| 45 inline SpinButtonElement::SpinButtonElement(Document& document, | |
| 46 SpinButtonOwner& spin_button_owner) | |
| 47 : HTMLDivElement(document), | |
| 48 spin_button_owner_(&spin_button_owner), | |
| 49 capturing_(false), | |
| 50 up_down_state_(kIndeterminate), | |
| 51 press_starting_state_(kIndeterminate), | |
| 52 repeating_timer_( | |
| 53 TaskRunnerHelper::Get(TaskType::kUnspecedTimer, &document), | |
| 54 this, | |
| 55 &SpinButtonElement::RepeatingTimerFired) {} | |
| 56 | |
| 57 SpinButtonElement* SpinButtonElement::Create( | |
| 58 Document& document, | |
| 59 SpinButtonOwner& spin_button_owner) { | |
| 60 SpinButtonElement* element = | |
| 61 new SpinButtonElement(document, spin_button_owner); | |
| 62 element->SetShadowPseudoId(AtomicString("-webkit-inner-spin-button")); | |
| 63 element->setAttribute(idAttr, ShadowElementNames::SpinButton()); | |
| 64 return element; | |
| 65 } | |
| 66 | |
| 67 void SpinButtonElement::DetachLayoutTree(const AttachContext& context) { | |
| 68 ReleaseCapture(kEventDispatchDisallowed); | |
| 69 HTMLDivElement::DetachLayoutTree(context); | |
| 70 } | |
| 71 | |
| 72 void SpinButtonElement::DefaultEventHandler(Event* event) { | |
| 73 if (!event->IsMouseEvent()) { | |
| 74 if (!event->DefaultHandled()) | |
| 75 HTMLDivElement::DefaultEventHandler(event); | |
| 76 return; | |
| 77 } | |
| 78 | |
| 79 LayoutBox* box = GetLayoutBox(); | |
| 80 if (!box) { | |
| 81 if (!event->DefaultHandled()) | |
| 82 HTMLDivElement::DefaultEventHandler(event); | |
| 83 return; | |
| 84 } | |
| 85 | |
| 86 if (!ShouldRespondToMouseEvents()) { | |
| 87 if (!event->DefaultHandled()) | |
| 88 HTMLDivElement::DefaultEventHandler(event); | |
| 89 return; | |
| 90 } | |
| 91 | |
| 92 MouseEvent* mouse_event = ToMouseEvent(event); | |
| 93 IntPoint local = RoundedIntPoint(box->AbsoluteToLocal( | |
| 94 FloatPoint(mouse_event->AbsoluteLocation()), kUseTransforms)); | |
| 95 if (mouse_event->type() == EventTypeNames::mousedown && | |
| 96 mouse_event->button() == | |
| 97 static_cast<short>(WebPointerProperties::Button::kLeft)) { | |
| 98 if (box->PixelSnappedBorderBoxRect().Contains(local)) { | |
| 99 if (spin_button_owner_) | |
| 100 spin_button_owner_->FocusAndSelectSpinButtonOwner(); | |
| 101 if (GetLayoutObject()) { | |
| 102 if (up_down_state_ != kIndeterminate) { | |
| 103 // A JavaScript event handler called in doStepAction() below | |
| 104 // might change the element state and we might need to | |
| 105 // cancel the repeating timer by the state change. If we | |
| 106 // started the timer after doStepAction(), we would have no | |
| 107 // chance to cancel the timer. | |
| 108 StartRepeatingTimer(); | |
| 109 DoStepAction(up_down_state_ == kUp ? 1 : -1); | |
| 110 } | |
| 111 } | |
| 112 event->SetDefaultHandled(); | |
| 113 } | |
| 114 } else if (mouse_event->type() == EventTypeNames::mouseup && | |
| 115 mouse_event->button() == | |
| 116 static_cast<short>(WebPointerProperties::Button::kLeft)) { | |
| 117 ReleaseCapture(); | |
| 118 } else if (event->type() == EventTypeNames::mousemove) { | |
| 119 if (box->PixelSnappedBorderBoxRect().Contains(local)) { | |
| 120 if (!capturing_) { | |
| 121 if (LocalFrame* frame = GetDocument().GetFrame()) { | |
| 122 frame->GetEventHandler().SetCapturingMouseEventsNode(this); | |
| 123 capturing_ = true; | |
| 124 if (Page* page = GetDocument().GetPage()) | |
| 125 page->GetChromeClient().RegisterPopupOpeningObserver(this); | |
| 126 } | |
| 127 } | |
| 128 UpDownState old_up_down_state = up_down_state_; | |
| 129 up_down_state_ = (local.Y() < box->Size().Height() / 2) ? kUp : kDown; | |
| 130 if (up_down_state_ != old_up_down_state) | |
| 131 GetLayoutObject()->SetShouldDoFullPaintInvalidation(); | |
| 132 } else { | |
| 133 ReleaseCapture(); | |
| 134 up_down_state_ = kIndeterminate; | |
| 135 } | |
| 136 } | |
| 137 | |
| 138 if (!event->DefaultHandled()) | |
| 139 HTMLDivElement::DefaultEventHandler(event); | |
| 140 } | |
| 141 | |
| 142 void SpinButtonElement::WillOpenPopup() { | |
| 143 ReleaseCapture(); | |
| 144 up_down_state_ = kIndeterminate; | |
| 145 } | |
| 146 | |
| 147 void SpinButtonElement::ForwardEvent(Event* event) { | |
| 148 if (!GetLayoutBox()) | |
| 149 return; | |
| 150 | |
| 151 if (!event->HasInterface(EventNames::WheelEvent)) | |
| 152 return; | |
| 153 | |
| 154 if (!spin_button_owner_) | |
| 155 return; | |
| 156 | |
| 157 if (!spin_button_owner_->ShouldSpinButtonRespondToWheelEvents()) | |
| 158 return; | |
| 159 | |
| 160 DoStepAction(ToWheelEvent(event)->wheelDeltaY()); | |
| 161 event->SetDefaultHandled(); | |
| 162 } | |
| 163 | |
| 164 bool SpinButtonElement::WillRespondToMouseMoveEvents() { | |
| 165 if (GetLayoutBox() && ShouldRespondToMouseEvents()) | |
| 166 return true; | |
| 167 | |
| 168 return HTMLDivElement::WillRespondToMouseMoveEvents(); | |
| 169 } | |
| 170 | |
| 171 bool SpinButtonElement::WillRespondToMouseClickEvents() { | |
| 172 if (GetLayoutBox() && ShouldRespondToMouseEvents()) | |
| 173 return true; | |
| 174 | |
| 175 return HTMLDivElement::WillRespondToMouseClickEvents(); | |
| 176 } | |
| 177 | |
| 178 void SpinButtonElement::DoStepAction(int amount) { | |
| 179 if (!spin_button_owner_) | |
| 180 return; | |
| 181 | |
| 182 if (amount > 0) | |
| 183 spin_button_owner_->SpinButtonStepUp(); | |
| 184 else if (amount < 0) | |
| 185 spin_button_owner_->SpinButtonStepDown(); | |
| 186 } | |
| 187 | |
| 188 void SpinButtonElement::ReleaseCapture(EventDispatch event_dispatch) { | |
| 189 StopRepeatingTimer(); | |
| 190 if (!capturing_) | |
| 191 return; | |
| 192 if (LocalFrame* frame = GetDocument().GetFrame()) { | |
| 193 frame->GetEventHandler().SetCapturingMouseEventsNode(nullptr); | |
| 194 capturing_ = false; | |
| 195 if (Page* page = GetDocument().GetPage()) | |
| 196 page->GetChromeClient().UnregisterPopupOpeningObserver(this); | |
| 197 } | |
| 198 if (spin_button_owner_) | |
| 199 spin_button_owner_->SpinButtonDidReleaseMouseCapture(event_dispatch); | |
| 200 } | |
| 201 | |
| 202 bool SpinButtonElement::MatchesReadOnlyPseudoClass() const { | |
| 203 return OwnerShadowHost()->MatchesReadOnlyPseudoClass(); | |
| 204 } | |
| 205 | |
| 206 bool SpinButtonElement::MatchesReadWritePseudoClass() const { | |
| 207 return OwnerShadowHost()->MatchesReadWritePseudoClass(); | |
| 208 } | |
| 209 | |
| 210 void SpinButtonElement::StartRepeatingTimer() { | |
| 211 press_starting_state_ = up_down_state_; | |
| 212 ScrollbarTheme& theme = ScrollbarTheme::GetTheme(); | |
| 213 repeating_timer_.Start(theme.InitialAutoscrollTimerDelay(), | |
| 214 theme.AutoscrollTimerDelay(), BLINK_FROM_HERE); | |
| 215 } | |
| 216 | |
| 217 void SpinButtonElement::StopRepeatingTimer() { | |
| 218 repeating_timer_.Stop(); | |
| 219 } | |
| 220 | |
| 221 void SpinButtonElement::Step(int amount) { | |
| 222 if (!ShouldRespondToMouseEvents()) | |
| 223 return; | |
| 224 // On Mac OS, NSStepper updates the value for the button under the mouse | |
| 225 // cursor regardless of the button pressed at the beginning. So the | |
| 226 // following check is not needed for Mac OS. | |
| 227 #if !OS(MACOSX) | |
| 228 if (up_down_state_ != press_starting_state_) | |
| 229 return; | |
| 230 #endif | |
| 231 DoStepAction(amount); | |
| 232 } | |
| 233 | |
| 234 void SpinButtonElement::RepeatingTimerFired(TimerBase*) { | |
| 235 if (up_down_state_ != kIndeterminate) | |
| 236 Step(up_down_state_ == kUp ? 1 : -1); | |
| 237 } | |
| 238 | |
| 239 void SpinButtonElement::SetHovered(bool flag) { | |
| 240 if (!flag) | |
| 241 up_down_state_ = kIndeterminate; | |
| 242 HTMLDivElement::SetHovered(flag); | |
| 243 } | |
| 244 | |
| 245 bool SpinButtonElement::ShouldRespondToMouseEvents() { | |
| 246 return !spin_button_owner_ || | |
| 247 spin_button_owner_->ShouldSpinButtonRespondToMouseEvents(); | |
| 248 } | |
| 249 | |
| 250 DEFINE_TRACE(SpinButtonElement) { | |
| 251 visitor->Trace(spin_button_owner_); | |
| 252 HTMLDivElement::Trace(visitor); | |
| 253 } | |
| 254 | |
| 255 } // namespace blink | |
| OLD | NEW |