| 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/mac/ScrollbarThemeMacNonOverlayAPI.h" |
| 33 |
| 34 #include <Carbon/Carbon.h> |
| 35 #include "core/platform/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 WebKit::WebThemeEngine::State scrollbarStateToThemeState(ScrollbarThemeCl
ient* scrollbar) |
| 72 { |
| 73 if (!scrollbar->enabled()) |
| 74 return WebKit::WebThemeEngine::StateDisabled; |
| 75 if (!scrollbar->isScrollableAreaActive()) |
| 76 return WebKit::WebThemeEngine::StateInactive; |
| 77 if (scrollbar->pressedPart() == ThumbPart) |
| 78 return WebKit::WebThemeEngine::StatePressed; |
| 79 |
| 80 return WebKit::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 WebKit::WebThemeEngine::ScrollbarInfo scrollbarInfo; |
| 154 scrollbarInfo.orientation = scrollbar->orientation() == HorizontalScroll
bar ? WebKit::WebThemeEngine::ScrollbarOrientationHorizontal : WebKit::WebThemeE
ngine::ScrollbarOrientationVertical; |
| 155 scrollbarInfo.parent = scrollbar->isScrollViewScrollbar() ? WebKit::WebT
hemeEngine::ScrollbarParentScrollView : WebKit::WebThemeEngine::ScrollbarParentR
enderLayer; |
| 156 scrollbarInfo.maxValue = scrollbar->maximum(); |
| 157 scrollbarInfo.currentValue = scrollbar->currentPos(); |
| 158 scrollbarInfo.visibleSize = scrollbar->visibleSize(); |
| 159 scrollbarInfo.totalSize = scrollbar->totalSize(); |
| 160 |
| 161 WebKit::WebCanvas* webCanvas = drawingContext->canvas(); |
| 162 WebKit::Platform::current()->themeEngine()->paintScrollbarThumb( |
| 163 webCanvas, |
| 164 scrollbarStateToThemeState(scrollbar), |
| 165 scrollbar->controlSize() == RegularScrollbar ? WebKit::WebThemeEngin
e::SizeRegular : WebKit::WebThemeEngine::SizeSmall, |
| 166 WebKit::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 |