| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | |
| 3 * | |
| 4 * Redistribution and use in source and binary forms, with or without | |
| 5 * modification, are permitted provided that the following conditions are | |
| 6 * met: | |
| 7 * | |
| 8 * * Redistributions of source code must retain the above copyright | |
| 9 * notice, this list of conditions and the following disclaimer. | |
| 10 * * Redistributions in binary form must reproduce the above | |
| 11 * copyright notice, this list of conditions and the following disclaimer | |
| 12 * in the documentation and/or other materials provided with the | |
| 13 * distribution. | |
| 14 * * Neither the name of Google Inc. nor the names of its | |
| 15 * contributors may be used to endorse or promote products derived from | |
| 16 * this software without specific prior written permission. | |
| 17 * | |
| 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 29 */ | |
| 30 | |
| 31 #include "config.h" | |
| 32 #include "core/platform/ScrollbarThemeMacNonOverlayAPI.h" | |
| 33 | |
| 34 #include <Carbon/Carbon.h> | |
| 35 #include "platform/scroll/ScrollbarThemeClient.h" | |
| 36 #include "public/platform/mac/WebThemeEngine.h" | |
| 37 #include "public/platform/Platform.h" | |
| 38 #include "public/platform/WebRect.h" | |
| 39 #include "skia/ext/skia_utils_mac.h" | |
| 40 | |
| 41 namespace WebCore { | |
| 42 | |
| 43 // FIXME: Get these numbers from CoreUI. | |
| 44 static int cRealButtonLength[] = { 28, 21 }; | |
| 45 static int cButtonHitInset[] = { 3, 2 }; | |
| 46 // cRealButtonLength - cButtonInset | |
| 47 static int cButtonLength[] = { 14, 10 }; | |
| 48 static int cScrollbarThickness[] = { 15, 11 }; | |
| 49 static int cButtonInset[] = { 14, 11 }; | |
| 50 static int cThumbMinLength[] = { 26, 20 }; | |
| 51 | |
| 52 static int cOuterButtonLength[] = { 16, 14 }; // The outer button in a double bu
tton pair is a bit bigger. | |
| 53 static int cOuterButtonOverlap = 2; | |
| 54 | |
| 55 static ScrollbarButtonsPlacement gButtonPlacement = ScrollbarButtonsDoubleEnd; | |
| 56 | |
| 57 void ScrollbarThemeMacNonOverlayAPI::updateButtonPlacement() | |
| 58 { | |
| 59 NSString *buttonPlacement = [[NSUserDefaults standardUserDefaults] objectFor
Key:@"AppleScrollBarVariant"]; | |
| 60 if ([buttonPlacement isEqualToString:@"Single"]) | |
| 61 gButtonPlacement = ScrollbarButtonsSingle; | |
| 62 else if ([buttonPlacement isEqualToString:@"DoubleMin"]) | |
| 63 gButtonPlacement = ScrollbarButtonsDoubleStart; | |
| 64 else if ([buttonPlacement isEqualToString:@"DoubleBoth"]) | |
| 65 gButtonPlacement = ScrollbarButtonsDoubleBoth; | |
| 66 else { | |
| 67 gButtonPlacement = ScrollbarButtonsDoubleEnd; | |
| 68 } | |
| 69 } | |
| 70 | |
| 71 static blink::WebThemeEngine::State scrollbarStateToThemeState(ScrollbarThemeCli
ent* scrollbar) | |
| 72 { | |
| 73 if (!scrollbar->enabled()) | |
| 74 return blink::WebThemeEngine::StateDisabled; | |
| 75 if (!scrollbar->isScrollableAreaActive()) | |
| 76 return blink::WebThemeEngine::StateInactive; | |
| 77 if (scrollbar->pressedPart() == ThumbPart) | |
| 78 return blink::WebThemeEngine::StatePressed; | |
| 79 | |
| 80 return blink::WebThemeEngine::StateActive; | |
| 81 } | |
| 82 | |
| 83 // Override ScrollbarThemeMacCommon::paint() to add support for the following: | |
| 84 // - drawing using WebThemeEngine functions | |
| 85 // - drawing tickmarks | |
| 86 // - Skia specific changes | |
| 87 bool ScrollbarThemeMacNonOverlayAPI::paint(ScrollbarThemeClient* scrollbar, Grap
hicsContext* context, const IntRect& damageRect) | |
| 88 { | |
| 89 // Get the tickmarks for the frameview. | |
| 90 Vector<IntRect> tickmarks; | |
| 91 scrollbar->getTickmarks(tickmarks); | |
| 92 | |
| 93 HIThemeTrackDrawInfo trackInfo; | |
| 94 trackInfo.version = 0; | |
| 95 trackInfo.kind = scrollbar->controlSize() == RegularScrollbar ? kThemeMedium
ScrollBar : kThemeSmallScrollBar; | |
| 96 trackInfo.bounds = scrollbar->frameRect(); | |
| 97 trackInfo.min = 0; | |
| 98 trackInfo.max = scrollbar->maximum(); | |
| 99 trackInfo.value = scrollbar->currentPos(); | |
| 100 trackInfo.trackInfo.scrollbar.viewsize = scrollbar->visibleSize(); | |
| 101 trackInfo.attributes = 0; | |
| 102 if (scrollbar->orientation() == HorizontalScrollbar) | |
| 103 trackInfo.attributes |= kThemeTrackHorizontal; | |
| 104 | |
| 105 if (!scrollbar->enabled()) | |
| 106 trackInfo.enableState = kThemeTrackDisabled; | |
| 107 else | |
| 108 trackInfo.enableState = scrollbar->isScrollableAreaActive() ? kThemeTrac
kActive : kThemeTrackInactive; | |
| 109 | |
| 110 if (!hasButtons(scrollbar)) | |
| 111 trackInfo.enableState = kThemeTrackNothingToScroll; | |
| 112 trackInfo.trackInfo.scrollbar.pressState = scrollbarPartToHIPressedState(scr
ollbar->pressedPart()); | |
| 113 | |
| 114 SkCanvas* canvas = context->canvas(); | |
| 115 CGAffineTransform currentCTM = gfx::SkMatrixToCGAffineTransform(canvas->getT
otalMatrix()); | |
| 116 | |
| 117 // The Aqua scrollbar is buggy when rotated and scaled. We will just draw i
nto a bitmap if we detect a scale or rotation. | |
| 118 bool canDrawDirectly = currentCTM.a == 1.0f && currentCTM.b == 0.0f && curre
ntCTM.c == 0.0f && (currentCTM.d == 1.0f || currentCTM.d == -1.0f); | |
| 119 GraphicsContext* drawingContext = context; | |
| 120 OwnPtr<ImageBuffer> imageBuffer; | |
| 121 if (!canDrawDirectly) { | |
| 122 trackInfo.bounds = IntRect(IntPoint(), scrollbar->frameRect().size()); | |
| 123 | |
| 124 IntRect bufferRect(scrollbar->frameRect()); | |
| 125 bufferRect.intersect(damageRect); | |
| 126 bufferRect.move(-scrollbar->frameRect().x(), -scrollbar->frameRect().y()
); | |
| 127 | |
| 128 imageBuffer = ImageBuffer::create(bufferRect.size()); | |
| 129 if (!imageBuffer) | |
| 130 return true; | |
| 131 | |
| 132 drawingContext = imageBuffer->context(); | |
| 133 } | |
| 134 | |
| 135 // Draw thumbless. | |
| 136 gfx::SkiaBitLocker bitLocker(drawingContext->canvas()); | |
| 137 CGContextRef cgContext = bitLocker.cgContext(); | |
| 138 HIThemeDrawTrack(&trackInfo, 0, cgContext, kHIThemeOrientationNormal); | |
| 139 | |
| 140 IntRect tickmarkTrackRect = trackRect(scrollbar, false); | |
| 141 if (!canDrawDirectly) { | |
| 142 tickmarkTrackRect.setX(0); | |
| 143 tickmarkTrackRect.setY(0); | |
| 144 } | |
| 145 // The ends are rounded and the thumb doesn't go there. | |
| 146 tickmarkTrackRect.inflateY(-tickmarkTrackRect.width()); | |
| 147 // Inset a bit. | |
| 148 tickmarkTrackRect.setX(tickmarkTrackRect.x() + 2); | |
| 149 tickmarkTrackRect.setWidth(tickmarkTrackRect.width() - 5); | |
| 150 paintGivenTickmarks(drawingContext, scrollbar, tickmarkTrackRect, tickmarks)
; | |
| 151 | |
| 152 if (hasThumb(scrollbar)) { | |
| 153 blink::WebThemeEngine::ScrollbarInfo scrollbarInfo; | |
| 154 scrollbarInfo.orientation = scrollbar->orientation() == HorizontalScroll
bar ? blink::WebThemeEngine::ScrollbarOrientationHorizontal : blink::WebThemeEng
ine::ScrollbarOrientationVertical; | |
| 155 scrollbarInfo.parent = scrollbar->isScrollViewScrollbar() ? blink::WebTh
emeEngine::ScrollbarParentScrollView : blink::WebThemeEngine::ScrollbarParentRen
derLayer; | |
| 156 scrollbarInfo.maxValue = scrollbar->maximum(); | |
| 157 scrollbarInfo.currentValue = scrollbar->currentPos(); | |
| 158 scrollbarInfo.visibleSize = scrollbar->visibleSize(); | |
| 159 scrollbarInfo.totalSize = scrollbar->totalSize(); | |
| 160 | |
| 161 blink::WebCanvas* webCanvas = drawingContext->canvas(); | |
| 162 blink::Platform::current()->themeEngine()->paintScrollbarThumb( | |
| 163 webCanvas, | |
| 164 scrollbarStateToThemeState(scrollbar), | |
| 165 scrollbar->controlSize() == RegularScrollbar ? blink::WebThemeEngine
::SizeRegular : blink::WebThemeEngine::SizeSmall, | |
| 166 blink::WebRect(scrollbar->frameRect()), | |
| 167 scrollbarInfo); | |
| 168 } | |
| 169 | |
| 170 if (!canDrawDirectly) | |
| 171 context->drawImageBuffer(imageBuffer.get(), scrollbar->frameRect().locat
ion()); | |
| 172 | |
| 173 return true; | |
| 174 } | |
| 175 | |
| 176 int ScrollbarThemeMacNonOverlayAPI::scrollbarThickness(ScrollbarControlSize cont
rolSize) | |
| 177 { | |
| 178 return cScrollbarThickness[controlSize]; | |
| 179 } | |
| 180 | |
| 181 ScrollbarButtonsPlacement ScrollbarThemeMacNonOverlayAPI::buttonsPlacement() con
st | |
| 182 { | |
| 183 return gButtonPlacement; | |
| 184 } | |
| 185 | |
| 186 bool ScrollbarThemeMacNonOverlayAPI::hasButtons(ScrollbarThemeClient* scrollbar) | |
| 187 { | |
| 188 return scrollbar->enabled() && buttonsPlacement() != ScrollbarButtonsNone | |
| 189 && (scrollbar->orientation() == HorizontalScrollbar | |
| 190 ? scrollbar->width() | |
| 191 : scrollbar->height()) >= 2 * (cRealButtonLength[scrollbar->control
Size()] - cButtonHitInset[scrollbar->controlSize()]); | |
| 192 } | |
| 193 | |
| 194 bool ScrollbarThemeMacNonOverlayAPI::hasThumb(ScrollbarThemeClient* scrollbar) | |
| 195 { | |
| 196 int minLengthForThumb = 2 * cButtonInset[scrollbar->controlSize()] + cThumbM
inLength[scrollbar->controlSize()] + 1; | |
| 197 return scrollbar->enabled() && (scrollbar->orientation() == HorizontalScroll
bar ? | |
| 198 scrollbar->width() : | |
| 199 scrollbar->height()) >= minLengthForThumb; | |
| 200 } | |
| 201 | |
| 202 static IntRect buttonRepaintRect(const IntRect& buttonRect, ScrollbarOrientation
orientation, ScrollbarControlSize controlSize, bool start) | |
| 203 { | |
| 204 ASSERT(gButtonPlacement != ScrollbarButtonsNone); | |
| 205 | |
| 206 IntRect paintRect(buttonRect); | |
| 207 if (orientation == HorizontalScrollbar) { | |
| 208 paintRect.setWidth(cRealButtonLength[controlSize]); | |
| 209 if (!start) | |
| 210 paintRect.setX(buttonRect.x() - (cRealButtonLength[controlSize] - bu
ttonRect.width())); | |
| 211 } else { | |
| 212 paintRect.setHeight(cRealButtonLength[controlSize]); | |
| 213 if (!start) | |
| 214 paintRect.setY(buttonRect.y() - (cRealButtonLength[controlSize] - bu
ttonRect.height())); | |
| 215 } | |
| 216 | |
| 217 return paintRect; | |
| 218 } | |
| 219 | |
| 220 IntRect ScrollbarThemeMacNonOverlayAPI::backButtonRect(ScrollbarThemeClient* scr
ollbar, ScrollbarPart part, bool painting) | |
| 221 { | |
| 222 IntRect result; | |
| 223 | |
| 224 if (part == BackButtonStartPart && (buttonsPlacement() == ScrollbarButtonsNo
ne || buttonsPlacement() == ScrollbarButtonsDoubleEnd)) | |
| 225 return result; | |
| 226 | |
| 227 if (part == BackButtonEndPart && (buttonsPlacement() == ScrollbarButtonsNone
|| buttonsPlacement() == ScrollbarButtonsDoubleStart || buttonsPlacement() == S
crollbarButtonsSingle)) | |
| 228 return result; | |
| 229 | |
| 230 int thickness = scrollbarThickness(scrollbar->controlSize()); | |
| 231 bool outerButton = part == BackButtonStartPart && (buttonsPlacement() == Scr
ollbarButtonsDoubleStart || buttonsPlacement() == ScrollbarButtonsDoubleBoth); | |
| 232 if (outerButton) { | |
| 233 if (scrollbar->orientation() == HorizontalScrollbar) | |
| 234 result = IntRect(scrollbar->x(), scrollbar->y(), cOuterButtonLength[
scrollbar->controlSize()] + (painting ? cOuterButtonOverlap : 0), thickness); | |
| 235 else | |
| 236 result = IntRect(scrollbar->x(), scrollbar->y(), thickness, cOuterBu
ttonLength[scrollbar->controlSize()] + (painting ? cOuterButtonOverlap : 0)); | |
| 237 return result; | |
| 238 } | |
| 239 | |
| 240 // Our repaint rect is slightly larger, since we are a button that is adjace
nt to the track. | |
| 241 if (scrollbar->orientation() == HorizontalScrollbar) { | |
| 242 int start = part == BackButtonStartPart ? scrollbar->x() : scrollbar->x(
) + scrollbar->width() - cOuterButtonLength[scrollbar->controlSize()] - cButtonL
ength[scrollbar->controlSize()]; | |
| 243 result = IntRect(start, scrollbar->y(), cButtonLength[scrollbar->control
Size()], thickness); | |
| 244 } else { | |
| 245 int start = part == BackButtonStartPart ? scrollbar->y() : scrollbar->y(
) + scrollbar->height() - cOuterButtonLength[scrollbar->controlSize()] - cButton
Length[scrollbar->controlSize()]; | |
| 246 result = IntRect(scrollbar->x(), start, thickness, cButtonLength[scrollb
ar->controlSize()]); | |
| 247 } | |
| 248 | |
| 249 if (painting) | |
| 250 return buttonRepaintRect(result, scrollbar->orientation(), scrollbar->co
ntrolSize(), part == BackButtonStartPart); | |
| 251 return result; | |
| 252 } | |
| 253 | |
| 254 IntRect ScrollbarThemeMacNonOverlayAPI::forwardButtonRect(ScrollbarThemeClient*
scrollbar, ScrollbarPart part, bool painting) | |
| 255 { | |
| 256 IntRect result; | |
| 257 | |
| 258 if (part == ForwardButtonEndPart && (buttonsPlacement() == ScrollbarButtonsN
one || buttonsPlacement() == ScrollbarButtonsDoubleStart)) | |
| 259 return result; | |
| 260 | |
| 261 if (part == ForwardButtonStartPart && (buttonsPlacement() == ScrollbarButton
sNone || buttonsPlacement() == ScrollbarButtonsDoubleEnd || buttonsPlacement() =
= ScrollbarButtonsSingle)) | |
| 262 return result; | |
| 263 | |
| 264 int thickness = scrollbarThickness(scrollbar->controlSize()); | |
| 265 int outerButtonLength = cOuterButtonLength[scrollbar->controlSize()]; | |
| 266 int buttonLength = cButtonLength[scrollbar->controlSize()]; | |
| 267 | |
| 268 bool outerButton = part == ForwardButtonEndPart && (buttonsPlacement() == Sc
rollbarButtonsDoubleEnd || buttonsPlacement() == ScrollbarButtonsDoubleBoth); | |
| 269 if (outerButton) { | |
| 270 if (scrollbar->orientation() == HorizontalScrollbar) { | |
| 271 result = IntRect(scrollbar->x() + scrollbar->width() - outerButtonLe
ngth, scrollbar->y(), outerButtonLength, thickness); | |
| 272 if (painting) | |
| 273 result.inflateX(cOuterButtonOverlap); | |
| 274 } else { | |
| 275 result = IntRect(scrollbar->x(), scrollbar->y() + scrollbar->height(
) - outerButtonLength, thickness, outerButtonLength); | |
| 276 if (painting) | |
| 277 result.inflateY(cOuterButtonOverlap); | |
| 278 } | |
| 279 return result; | |
| 280 } | |
| 281 | |
| 282 if (scrollbar->orientation() == HorizontalScrollbar) { | |
| 283 int start = part == ForwardButtonEndPart ? scrollbar->x() + scrollbar->w
idth() - buttonLength : scrollbar->x() + outerButtonLength; | |
| 284 result = IntRect(start, scrollbar->y(), buttonLength, thickness); | |
| 285 } else { | |
| 286 int start = part == ForwardButtonEndPart ? scrollbar->y() + scrollbar->h
eight() - buttonLength : scrollbar->y() + outerButtonLength; | |
| 287 result = IntRect(scrollbar->x(), start, thickness, buttonLength); | |
| 288 } | |
| 289 if (painting) | |
| 290 return buttonRepaintRect(result, scrollbar->orientation(), scrollbar->co
ntrolSize(), part == ForwardButtonStartPart); | |
| 291 return result; | |
| 292 } | |
| 293 | |
| 294 IntRect ScrollbarThemeMacNonOverlayAPI::trackRect(ScrollbarThemeClient* scrollba
r, bool painting) | |
| 295 { | |
| 296 if (painting || !hasButtons(scrollbar)) | |
| 297 return scrollbar->frameRect(); | |
| 298 | |
| 299 IntRect result; | |
| 300 int thickness = scrollbarThickness(scrollbar->controlSize()); | |
| 301 int startWidth = 0; | |
| 302 int endWidth = 0; | |
| 303 int outerButtonLength = cOuterButtonLength[scrollbar->controlSize()]; | |
| 304 int buttonLength = cButtonLength[scrollbar->controlSize()]; | |
| 305 int doubleButtonLength = outerButtonLength + buttonLength; | |
| 306 switch (buttonsPlacement()) { | |
| 307 case ScrollbarButtonsSingle: | |
| 308 startWidth = buttonLength; | |
| 309 endWidth = buttonLength; | |
| 310 break; | |
| 311 case ScrollbarButtonsDoubleStart: | |
| 312 startWidth = doubleButtonLength; | |
| 313 break; | |
| 314 case ScrollbarButtonsDoubleEnd: | |
| 315 endWidth = doubleButtonLength; | |
| 316 break; | |
| 317 case ScrollbarButtonsDoubleBoth: | |
| 318 startWidth = doubleButtonLength; | |
| 319 endWidth = doubleButtonLength; | |
| 320 break; | |
| 321 default: | |
| 322 break; | |
| 323 } | |
| 324 | |
| 325 int totalWidth = startWidth + endWidth; | |
| 326 if (scrollbar->orientation() == HorizontalScrollbar) | |
| 327 return IntRect(scrollbar->x() + startWidth, scrollbar->y(), scrollbar->w
idth() - totalWidth, thickness); | |
| 328 return IntRect(scrollbar->x(), scrollbar->y() + startWidth, thickness, scrol
lbar->height() - totalWidth); | |
| 329 } | |
| 330 | |
| 331 int ScrollbarThemeMacNonOverlayAPI::minimumThumbLength(ScrollbarThemeClient* scr
ollbar) | |
| 332 { | |
| 333 return cThumbMinLength[scrollbar->controlSize()]; | |
| 334 } | |
| 335 | |
| 336 } | |
| OLD | NEW |