| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2011 Apple Inc. All Rights Reserved. | 2 * Copyright (C) 2011 Apple Inc. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| 11 * documentation and/or other materials provided with the distribution. | 11 * documentation and/or other materials provided with the distribution. |
| 12 * | 12 * |
| 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 24 */ | 24 */ |
| 25 | 25 |
| 26 #include "config.h" | 26 #include "config.h" |
| 27 #include "platform/scroll/ScrollbarTheme.h" | 27 #include "platform/scroll/ScrollbarTheme.h" |
| 28 | 28 |
| 29 #include "RuntimeEnabledFeatures.h" | 29 #include "RuntimeEnabledFeatures.h" |
| 30 #include "platform/PlatformMouseEvent.h" |
| 30 #include "platform/scroll/ScrollbarThemeClient.h" | 31 #include "platform/scroll/ScrollbarThemeClient.h" |
| 31 #include "platform/scroll/ScrollbarThemeMock.h" | 32 #include "platform/scroll/ScrollbarThemeMock.h" |
| 32 #include "platform/scroll/ScrollbarThemeOverlayMock.h" | 33 #include "platform/scroll/ScrollbarThemeOverlayMock.h" |
| 34 #include "public/platform/Platform.h" |
| 35 #include "public/platform/WebPoint.h" |
| 36 #include "public/platform/WebScrollbarBehavior.h" |
| 33 | 37 |
| 34 #if !OS(MACOSX) | 38 #if !OS(MACOSX) |
| 35 #include "public/platform/Platform.h" | |
| 36 #include "public/platform/WebRect.h" | 39 #include "public/platform/WebRect.h" |
| 37 #include "public/platform/WebThemeEngine.h" | 40 #include "public/platform/WebThemeEngine.h" |
| 38 #endif | 41 #endif |
| 39 | 42 |
| 40 namespace WebCore { | 43 namespace WebCore { |
| 41 | 44 |
| 42 ScrollbarTheme* ScrollbarTheme::theme() | |
| 43 { | |
| 44 if (ScrollbarTheme::mockScrollbarsEnabled()) { | |
| 45 if (RuntimeEnabledFeatures::overlayScrollbarsEnabled()) { | |
| 46 DEFINE_STATIC_LOCAL(ScrollbarThemeOverlayMock, overlayMockTheme, ())
; | |
| 47 return &overlayMockTheme; | |
| 48 } | |
| 49 | |
| 50 DEFINE_STATIC_LOCAL(ScrollbarThemeMock, mockTheme, ()); | |
| 51 return &mockTheme; | |
| 52 } | |
| 53 return nativeTheme(); | |
| 54 } | |
| 55 | |
| 56 bool ScrollbarTheme::gMockScrollbarsEnabled = false; | 45 bool ScrollbarTheme::gMockScrollbarsEnabled = false; |
| 57 | 46 |
| 58 void ScrollbarTheme::setMockScrollbarsEnabled(bool flag) | |
| 59 { | |
| 60 gMockScrollbarsEnabled = flag; | |
| 61 } | |
| 62 | |
| 63 bool ScrollbarTheme::mockScrollbarsEnabled() | |
| 64 { | |
| 65 return gMockScrollbarsEnabled; | |
| 66 } | |
| 67 | |
| 68 bool ScrollbarTheme::paint(ScrollbarThemeClient* scrollbar, GraphicsContext* gra
phicsContext, const IntRect& damageRect) | 47 bool ScrollbarTheme::paint(ScrollbarThemeClient* scrollbar, GraphicsContext* gra
phicsContext, const IntRect& damageRect) |
| 69 { | 48 { |
| 70 // Create the ScrollbarControlPartMask based on the damageRect | 49 // Create the ScrollbarControlPartMask based on the damageRect |
| 71 ScrollbarControlPartMask scrollMask = NoPart; | 50 ScrollbarControlPartMask scrollMask = NoPart; |
| 72 | 51 |
| 73 IntRect backButtonStartPaintRect; | 52 IntRect backButtonStartPaintRect; |
| 74 IntRect backButtonEndPaintRect; | 53 IntRect backButtonEndPaintRect; |
| 75 IntRect forwardButtonStartPaintRect; | 54 IntRect forwardButtonStartPaintRect; |
| 76 IntRect forwardButtonEndPaintRect; | 55 IntRect forwardButtonEndPaintRect; |
| 77 if (hasButtons(scrollbar)) { | 56 if (hasButtons(scrollbar)) { |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 else if (part == ForwardTrackPart) | 192 else if (part == ForwardTrackPart) |
| 214 result = afterThumbRect; | 193 result = afterThumbRect; |
| 215 else | 194 else |
| 216 result = thumbRect; | 195 result = thumbRect; |
| 217 } | 196 } |
| 218 } | 197 } |
| 219 result.moveBy(-scrollbar->location()); | 198 result.moveBy(-scrollbar->location()); |
| 220 scrollbar->invalidateRect(result); | 199 scrollbar->invalidateRect(result); |
| 221 } | 200 } |
| 222 | 201 |
| 223 void ScrollbarTheme::splitTrack(ScrollbarThemeClient* scrollbar, const IntRect&
unconstrainedTrackRect, IntRect& beforeThumbRect, IntRect& thumbRect, IntRect& a
fterThumbRect) | 202 void ScrollbarTheme::paintScrollCorner(GraphicsContext* context, const IntRect&
cornerRect) |
| 224 { | 203 { |
| 225 // This function won't even get called unless we're big enough to have some
combination of these three rects where at least | 204 if (cornerRect.isEmpty()) |
| 226 // one of them is non-empty. | 205 return; |
| 227 IntRect trackRect = constrainTrackRectToTrackPieces(scrollbar, unconstrained
TrackRect); | 206 |
| 228 int thumbPos = thumbPosition(scrollbar); | 207 #if OS(MACOSX) |
| 229 if (scrollbar->orientation() == HorizontalScrollbar) { | 208 context->fillRect(cornerRect, Color::white); |
| 230 thumbRect = IntRect(trackRect.x() + thumbPos, trackRect.y(), thumbLength
(scrollbar), scrollbar->height()); | 209 #else |
| 231 beforeThumbRect = IntRect(trackRect.x(), trackRect.y(), thumbPos + thumb
Rect.width() / 2, trackRect.height()); | 210 blink::Platform::current()->themeEngine()->paint(context->canvas(), blink::W
ebThemeEngine::PartScrollbarCorner, blink::WebThemeEngine::StateNormal, blink::W
ebRect(cornerRect), 0); |
| 232 afterThumbRect = IntRect(trackRect.x() + beforeThumbRect.width(), trackR
ect.y(), trackRect.maxX() - beforeThumbRect.maxX(), trackRect.height()); | 211 #endif |
| 233 } else { | 212 } |
| 234 thumbRect = IntRect(trackRect.x(), trackRect.y() + thumbPos, scrollbar->
width(), thumbLength(scrollbar)); | 213 |
| 235 beforeThumbRect = IntRect(trackRect.x(), trackRect.y(), trackRect.width(
), thumbPos + thumbRect.height() / 2); | 214 void ScrollbarTheme::paintOverhangBackground(GraphicsContext* context, const Int
Rect& horizontalOverhangRect, const IntRect& verticalOverhangRect, const IntRect
& dirtyRect) |
| 236 afterThumbRect = IntRect(trackRect.x(), trackRect.y() + beforeThumbRect.
height(), trackRect.width(), trackRect.maxY() - beforeThumbRect.maxY()); | 215 { |
| 237 } | 216 context->setFillColor(Color::white); |
| 217 if (!horizontalOverhangRect.isEmpty()) |
| 218 context->fillRect(intersection(horizontalOverhangRect, dirtyRect)); |
| 219 if (!verticalOverhangRect.isEmpty()) |
| 220 context->fillRect(intersection(verticalOverhangRect, dirtyRect)); |
| 221 } |
| 222 |
| 223 bool ScrollbarTheme::shouldCenterOnThumb(ScrollbarThemeClient* scrollbar, const
PlatformMouseEvent& evt) |
| 224 { |
| 225 return blink::Platform::current()->scrollbarBehavior()->shouldCenterOnThumb(
static_cast<blink::WebScrollbarBehavior::Button>(evt.button()), evt.shiftKey(),
evt.altKey()); |
| 226 } |
| 227 |
| 228 bool ScrollbarTheme::shouldSnapBackToDragOrigin(ScrollbarThemeClient* scrollbar,
const PlatformMouseEvent& evt) |
| 229 { |
| 230 IntPoint mousePosition = scrollbar->convertFromContainingWindow(evt.position
()); |
| 231 mousePosition.move(scrollbar->x(), scrollbar->y()); |
| 232 return blink::Platform::current()->scrollbarBehavior()->shouldSnapBackToDrag
Origin(mousePosition, trackRect(scrollbar), scrollbar->orientation() == Horizont
alScrollbar); |
| 238 } | 233 } |
| 239 | 234 |
| 240 // Returns the size represented by track taking into account scrolling past | 235 // Returns the size represented by track taking into account scrolling past |
| 241 // the end of the document. | 236 // the end of the document. |
| 242 static float usedTotalSize(ScrollbarThemeClient* scrollbar) | 237 static float usedTotalSize(ScrollbarThemeClient* scrollbar) |
| 243 { | 238 { |
| 244 float overhangAtStart = -scrollbar->currentPos(); | 239 float overhangAtStart = -scrollbar->currentPos(); |
| 245 float overhangAtEnd = scrollbar->currentPos() + scrollbar->visibleSize() - s
crollbar->totalSize(); | 240 float overhangAtEnd = scrollbar->currentPos() + scrollbar->visibleSize() - s
crollbar->totalSize(); |
| 246 float overhang = std::max(0.0f, std::max(overhangAtStart, overhangAtEnd)); | 241 float overhang = std::max(0.0f, std::max(overhangAtStart, overhangAtEnd)); |
| 247 return scrollbar->totalSize() + overhang; | 242 return scrollbar->totalSize() + overhang; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 272 overhang = scrollbar->currentPos() + scrollbar->visibleSize() - scrollba
r->totalSize(); | 267 overhang = scrollbar->currentPos() + scrollbar->visibleSize() - scrollba
r->totalSize(); |
| 273 float proportion = (scrollbar->visibleSize() - overhang) / usedTotalSize(scr
ollbar); | 268 float proportion = (scrollbar->visibleSize() - overhang) / usedTotalSize(scr
ollbar); |
| 274 int trackLen = trackLength(scrollbar); | 269 int trackLen = trackLength(scrollbar); |
| 275 int length = round(proportion * trackLen); | 270 int length = round(proportion * trackLen); |
| 276 length = std::max(length, minimumThumbLength(scrollbar)); | 271 length = std::max(length, minimumThumbLength(scrollbar)); |
| 277 if (length > trackLen) | 272 if (length > trackLen) |
| 278 length = 0; // Once the thumb is below the track length, it just goes aw
ay (to make more room for the track). | 273 length = 0; // Once the thumb is below the track length, it just goes aw
ay (to make more room for the track). |
| 279 return length; | 274 return length; |
| 280 } | 275 } |
| 281 | 276 |
| 282 int ScrollbarTheme::minimumThumbLength(ScrollbarThemeClient* scrollbar) | |
| 283 { | |
| 284 return scrollbarThickness(scrollbar->controlSize()); | |
| 285 } | |
| 286 | |
| 287 int ScrollbarTheme::trackPosition(ScrollbarThemeClient* scrollbar) | 277 int ScrollbarTheme::trackPosition(ScrollbarThemeClient* scrollbar) |
| 288 { | 278 { |
| 289 IntRect constrainedTrackRect = constrainTrackRectToTrackPieces(scrollbar, tr
ackRect(scrollbar)); | 279 IntRect constrainedTrackRect = constrainTrackRectToTrackPieces(scrollbar, tr
ackRect(scrollbar)); |
| 290 return (scrollbar->orientation() == HorizontalScrollbar) ? constrainedTrackR
ect.x() - scrollbar->x() : constrainedTrackRect.y() - scrollbar->y(); | 280 return (scrollbar->orientation() == HorizontalScrollbar) ? constrainedTrackR
ect.x() - scrollbar->x() : constrainedTrackRect.y() - scrollbar->y(); |
| 291 } | 281 } |
| 292 | 282 |
| 293 int ScrollbarTheme::trackLength(ScrollbarThemeClient* scrollbar) | 283 int ScrollbarTheme::trackLength(ScrollbarThemeClient* scrollbar) |
| 294 { | 284 { |
| 295 IntRect constrainedTrackRect = constrainTrackRectToTrackPieces(scrollbar, tr
ackRect(scrollbar)); | 285 IntRect constrainedTrackRect = constrainTrackRectToTrackPieces(scrollbar, tr
ackRect(scrollbar)); |
| 296 return (scrollbar->orientation() == HorizontalScrollbar) ? constrainedTrackR
ect.width() : constrainedTrackRect.height(); | 286 return (scrollbar->orientation() == HorizontalScrollbar) ? constrainedTrackR
ect.width() : constrainedTrackRect.height(); |
| 297 } | 287 } |
| 298 | 288 |
| 299 void ScrollbarTheme::paintScrollCorner(GraphicsContext* context, const IntRect&
cornerRect) | |
| 300 { | |
| 301 if (cornerRect.isEmpty()) | |
| 302 return; | |
| 303 | |
| 304 #if OS(MACOSX) | |
| 305 context->fillRect(cornerRect, Color::white); | |
| 306 #else | |
| 307 blink::Platform::current()->themeEngine()->paint(context->canvas(), blink::W
ebThemeEngine::PartScrollbarCorner, blink::WebThemeEngine::StateNormal, blink::W
ebRect(cornerRect), 0); | |
| 308 #endif | |
| 309 } | |
| 310 | |
| 311 IntRect ScrollbarTheme::thumbRect(ScrollbarThemeClient* scrollbar) | 289 IntRect ScrollbarTheme::thumbRect(ScrollbarThemeClient* scrollbar) |
| 312 { | 290 { |
| 313 if (!hasThumb(scrollbar)) | 291 if (!hasThumb(scrollbar)) |
| 314 return IntRect(); | 292 return IntRect(); |
| 315 | 293 |
| 316 IntRect track = trackRect(scrollbar); | 294 IntRect track = trackRect(scrollbar); |
| 317 IntRect startTrackRect; | 295 IntRect startTrackRect; |
| 318 IntRect thumbRect; | 296 IntRect thumbRect; |
| 319 IntRect endTrackRect; | 297 IntRect endTrackRect; |
| 320 splitTrack(scrollbar, track, startTrackRect, thumbRect, endTrackRect); | 298 splitTrack(scrollbar, track, startTrackRect, thumbRect, endTrackRect); |
| 321 | 299 |
| 322 return thumbRect; | 300 return thumbRect; |
| 323 } | 301 } |
| 324 | 302 |
| 325 int ScrollbarTheme::thumbThickness(ScrollbarThemeClient* scrollbar) | 303 int ScrollbarTheme::thumbThickness(ScrollbarThemeClient* scrollbar) |
| 326 { | 304 { |
| 327 IntRect track = trackRect(scrollbar); | 305 IntRect track = trackRect(scrollbar); |
| 328 return scrollbar->orientation() == HorizontalScrollbar ? track.height() : tr
ack.width(); | 306 return scrollbar->orientation() == HorizontalScrollbar ? track.height() : tr
ack.width(); |
| 329 } | 307 } |
| 330 | 308 |
| 331 void ScrollbarTheme::paintOverhangBackground(GraphicsContext* context, const Int
Rect& horizontalOverhangRect, const IntRect& verticalOverhangRect, const IntRect
& dirtyRect) | 309 int ScrollbarTheme::minimumThumbLength(ScrollbarThemeClient* scrollbar) |
| 332 { | 310 { |
| 333 context->setFillColor(Color::white); | 311 return scrollbarThickness(scrollbar->controlSize()); |
| 334 if (!horizontalOverhangRect.isEmpty()) | 312 } |
| 335 context->fillRect(intersection(horizontalOverhangRect, dirtyRect)); | 313 |
| 336 if (!verticalOverhangRect.isEmpty()) | 314 void ScrollbarTheme::splitTrack(ScrollbarThemeClient* scrollbar, const IntRect&
unconstrainedTrackRect, IntRect& beforeThumbRect, IntRect& thumbRect, IntRect& a
fterThumbRect) |
| 337 context->fillRect(intersection(verticalOverhangRect, dirtyRect)); | 315 { |
| 316 // This function won't even get called unless we're big enough to have some
combination of these three rects where at least |
| 317 // one of them is non-empty. |
| 318 IntRect trackRect = constrainTrackRectToTrackPieces(scrollbar, unconstrained
TrackRect); |
| 319 int thumbPos = thumbPosition(scrollbar); |
| 320 if (scrollbar->orientation() == HorizontalScrollbar) { |
| 321 thumbRect = IntRect(trackRect.x() + thumbPos, trackRect.y(), thumbLength
(scrollbar), scrollbar->height()); |
| 322 beforeThumbRect = IntRect(trackRect.x(), trackRect.y(), thumbPos + thumb
Rect.width() / 2, trackRect.height()); |
| 323 afterThumbRect = IntRect(trackRect.x() + beforeThumbRect.width(), trackR
ect.y(), trackRect.maxX() - beforeThumbRect.maxX(), trackRect.height()); |
| 324 } else { |
| 325 thumbRect = IntRect(trackRect.x(), trackRect.y() + thumbPos, scrollbar->
width(), thumbLength(scrollbar)); |
| 326 beforeThumbRect = IntRect(trackRect.x(), trackRect.y(), trackRect.width(
), thumbPos + thumbRect.height() / 2); |
| 327 afterThumbRect = IntRect(trackRect.x(), trackRect.y() + beforeThumbRect.
height(), trackRect.width(), trackRect.maxY() - beforeThumbRect.maxY()); |
| 328 } |
| 329 } |
| 330 |
| 331 ScrollbarTheme* ScrollbarTheme::theme() |
| 332 { |
| 333 if (ScrollbarTheme::mockScrollbarsEnabled()) { |
| 334 if (RuntimeEnabledFeatures::overlayScrollbarsEnabled()) { |
| 335 DEFINE_STATIC_LOCAL(ScrollbarThemeOverlayMock, overlayMockTheme, ())
; |
| 336 return &overlayMockTheme; |
| 337 } |
| 338 |
| 339 DEFINE_STATIC_LOCAL(ScrollbarThemeMock, mockTheme, ()); |
| 340 return &mockTheme; |
| 341 } |
| 342 return nativeTheme(); |
| 343 } |
| 344 |
| 345 void ScrollbarTheme::setMockScrollbarsEnabled(bool flag) |
| 346 { |
| 347 gMockScrollbarsEnabled = flag; |
| 348 } |
| 349 |
| 350 bool ScrollbarTheme::mockScrollbarsEnabled() |
| 351 { |
| 352 return gMockScrollbarsEnabled; |
| 338 } | 353 } |
| 339 | 354 |
| 340 } | 355 } |
| OLD | NEW |