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 |