Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / rendering / RenderThemeChromiumSkia.cpp
1 /*
2  * Copyright (C) 2007 Apple Inc.
3  * Copyright (C) 2007 Alp Toker <alp@atoker.com>
4  * Copyright (C) 2008 Collabora Ltd.
5  * Copyright (C) 2008, 2009 Google Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  */
23
24 #include "config.h"
25 #include "core/rendering/RenderThemeChromiumSkia.h"
26
27 #include "core/UserAgentStyleSheets.h"
28 #include "core/rendering/PaintInfo.h"
29 #include "core/rendering/RenderBox.h"
30 #include "core/rendering/RenderMediaControls.h"
31 #include "core/rendering/RenderObject.h"
32 #include "core/rendering/RenderProgress.h"
33 #include "core/rendering/RenderThemeChromiumFontProvider.h"
34 #include "platform/LayoutTestSupport.h"
35 #include "platform/graphics/GraphicsContext.h"
36 #include "platform/graphics/Image.h"
37 #include "platform/scroll/ScrollbarTheme.h"
38 #include "wtf/CurrentTime.h"
39 #include "wtf/StdLibExtras.h"
40
41 namespace blink {
42
43 enum PaddingType {
44     TopPadding,
45     RightPadding,
46     BottomPadding,
47     LeftPadding
48 };
49
50 static const int styledMenuListInternalPadding[4] = { 1, 4, 1, 4 };
51
52 // These values all match Safari/Win.
53 static const float defaultControlFontPixelSize = 13;
54 static const float defaultCancelButtonSize = 9;
55 static const float minCancelButtonSize = 5;
56 static const float maxCancelButtonSize = 21;
57 static const float defaultSearchFieldResultsDecorationSize = 13;
58 static const float minSearchFieldResultsDecorationSize = 9;
59 static const float maxSearchFieldResultsDecorationSize = 30;
60
61 RenderThemeChromiumSkia::RenderThemeChromiumSkia()
62 {
63 }
64
65 RenderThemeChromiumSkia::~RenderThemeChromiumSkia()
66 {
67 }
68
69 // Use the Windows style sheets to match their metrics.
70 String RenderThemeChromiumSkia::extraDefaultStyleSheet()
71 {
72     return RenderTheme::extraDefaultStyleSheet() +
73         String(themeWinCss, sizeof(themeWinCss)) +
74         String(themeChromiumSkiaCss, sizeof(themeChromiumSkiaCss)) +
75         String(themeChromiumCss, sizeof(themeChromiumCss));
76 }
77
78 String RenderThemeChromiumSkia::extraQuirksStyleSheet()
79 {
80     return String(themeWinQuirksCss, sizeof(themeWinQuirksCss));
81 }
82
83 bool RenderThemeChromiumSkia::supportsHover(const RenderStyle* style) const
84 {
85     return true;
86 }
87
88 bool RenderThemeChromiumSkia::supportsFocusRing(const RenderStyle* style) const
89 {
90     // This causes WebKit to draw the focus rings for us.
91     return false;
92 }
93
94 Color RenderThemeChromiumSkia::platformActiveSelectionBackgroundColor() const
95 {
96     return Color(0x1e, 0x90, 0xff);
97 }
98
99 Color RenderThemeChromiumSkia::platformInactiveSelectionBackgroundColor() const
100 {
101     return Color(0xc8, 0xc8, 0xc8);
102 }
103
104 Color RenderThemeChromiumSkia::platformActiveSelectionForegroundColor() const
105 {
106     return Color::black;
107 }
108
109 Color RenderThemeChromiumSkia::platformInactiveSelectionForegroundColor() const
110 {
111     return Color(0x32, 0x32, 0x32);
112 }
113
114 Color RenderThemeChromiumSkia::platformFocusRingColor() const
115 {
116     static Color focusRingColor(229, 151, 0, 255);
117     return focusRingColor;
118 }
119
120 double RenderThemeChromiumSkia::caretBlinkInterval() const
121 {
122     // Disable the blinking caret in layout test mode, as it introduces
123     // a race condition for the pixel tests. http://b/1198440
124     if (LayoutTestSupport::isRunningLayoutTest())
125         return 0;
126
127     return caretBlinkIntervalInternal();
128 }
129
130 void RenderThemeChromiumSkia::systemFont(CSSValueID systemFontID, FontStyle& fontStyle, FontWeight& fontWeight, float& fontSize, AtomicString& fontFamily) const
131 {
132     RenderThemeChromiumFontProvider::systemFont(systemFontID, fontStyle, fontWeight, fontSize, fontFamily);
133 }
134
135 int RenderThemeChromiumSkia::minimumMenuListSize(RenderStyle* style) const
136 {
137     return 0;
138 }
139
140 // These are the default dimensions of radio buttons and checkboxes.
141 static const int widgetStandardWidth = 13;
142 static const int widgetStandardHeight = 13;
143
144 // Return a rectangle that has the same center point as |original|, but with a
145 // size capped at |width| by |height|.
146 IntRect center(const IntRect& original, int width, int height)
147 {
148     width = std::min(original.width(), width);
149     height = std::min(original.height(), height);
150     int x = original.x() + (original.width() - width) / 2;
151     int y = original.y() + (original.height() - height) / 2;
152
153     return IntRect(x, y, width, height);
154 }
155
156 void RenderThemeChromiumSkia::setCheckboxSize(RenderStyle* style) const
157 {
158     // If the width and height are both specified, then we have nothing to do.
159     if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
160         return;
161
162     // FIXME:  A hard-coded size of 13 is used.  This is wrong but necessary
163     // for now.  It matches Firefox.  At different DPI settings on Windows,
164     // querying the theme gives you a larger size that accounts for the higher
165     // DPI.  Until our entire engine honors a DPI setting other than 96, we
166     // can't rely on the theme's metrics.
167     const IntSize size(widgetStandardWidth, widgetStandardHeight);
168     setSizeIfAuto(style, size);
169 }
170
171 void RenderThemeChromiumSkia::setRadioSize(RenderStyle* style) const
172 {
173     // Use same sizing for radio box as checkbox.
174     setCheckboxSize(style);
175 }
176
177 void RenderThemeChromiumSkia::adjustButtonStyle(RenderStyle* style, Element*) const
178 {
179     if (style->appearance() == PushButtonPart) {
180         // Ignore line-height.
181         style->setLineHeight(RenderStyle::initialLineHeight());
182     }
183 }
184
185 bool RenderThemeChromiumSkia::paintTextArea(RenderObject* o, const PaintInfo& i, const IntRect& r)
186 {
187     return paintTextField(o, i, r);
188 }
189
190 void RenderThemeChromiumSkia::adjustSearchFieldStyle(RenderStyle* style, Element*) const
191 {
192      // Ignore line-height.
193      style->setLineHeight(RenderStyle::initialLineHeight());
194 }
195
196 bool RenderThemeChromiumSkia::paintSearchField(RenderObject* o, const PaintInfo& i, const IntRect& r)
197 {
198     return paintTextField(o, i, r);
199 }
200
201 void RenderThemeChromiumSkia::adjustSearchFieldCancelButtonStyle(RenderStyle* style, Element*) const
202 {
203     // Scale the button size based on the font size
204     float fontScale = style->fontSize() / defaultControlFontPixelSize;
205     int cancelButtonSize = lroundf(std::min(std::max(minCancelButtonSize, defaultCancelButtonSize * fontScale), maxCancelButtonSize));
206     style->setWidth(Length(cancelButtonSize, Fixed));
207     style->setHeight(Length(cancelButtonSize, Fixed));
208 }
209
210 IntRect RenderThemeChromiumSkia::convertToPaintingRect(RenderObject* inputRenderer, const RenderObject* partRenderer, LayoutRect partRect, const IntRect& localOffset) const
211 {
212     // Compute an offset between the part renderer and the input renderer.
213     LayoutSize offsetFromInputRenderer = -partRenderer->offsetFromAncestorContainer(inputRenderer);
214     // Move the rect into partRenderer's coords.
215     partRect.move(offsetFromInputRenderer);
216     // Account for the local drawing offset.
217     partRect.move(localOffset.x(), localOffset.y());
218
219     return pixelSnappedIntRect(partRect);
220 }
221
222 bool RenderThemeChromiumSkia::paintSearchFieldCancelButton(RenderObject* cancelButtonObject, const PaintInfo& paintInfo, const IntRect& r)
223 {
224     // Get the renderer of <input> element.
225     if (!cancelButtonObject->node())
226         return false;
227     Node* input = cancelButtonObject->node()->shadowHost();
228     RenderObject* baseRenderer = input ? input->renderer() : cancelButtonObject;
229     if (!baseRenderer->isBox())
230         return false;
231     RenderBox* inputRenderBox = toRenderBox(baseRenderer);
232     LayoutRect inputContentBox = inputRenderBox->contentBoxRect();
233
234     // Make sure the scaled button stays square and will fit in its parent's box.
235     LayoutUnit cancelButtonSize = std::min(inputContentBox.width(), std::min<LayoutUnit>(inputContentBox.height(), r.height()));
236     // Calculate cancel button's coordinates relative to the input element.
237     // Center the button vertically.  Round up though, so if it has to be one pixel off-center, it will
238     // be one pixel closer to the bottom of the field.  This tends to look better with the text.
239     LayoutRect cancelButtonRect(cancelButtonObject->offsetFromAncestorContainer(inputRenderBox).width(),
240                                 inputContentBox.y() + (inputContentBox.height() - cancelButtonSize + 1) / 2,
241                                 cancelButtonSize, cancelButtonSize);
242     IntRect paintingRect = convertToPaintingRect(inputRenderBox, cancelButtonObject, cancelButtonRect, r);
243
244     DEFINE_STATIC_REF(Image, cancelImage, (Image::loadPlatformResource("searchCancel")));
245     DEFINE_STATIC_REF(Image, cancelPressedImage, (Image::loadPlatformResource("searchCancelPressed")));
246     paintInfo.context->drawImage(isPressed(cancelButtonObject) ? cancelPressedImage : cancelImage, paintingRect);
247     return false;
248 }
249
250 void RenderThemeChromiumSkia::adjustSearchFieldDecorationStyle(RenderStyle* style, Element*) const
251 {
252     IntSize emptySize(1, 11);
253     style->setWidth(Length(emptySize.width(), Fixed));
254     style->setHeight(Length(emptySize.height(), Fixed));
255 }
256
257 void RenderThemeChromiumSkia::adjustSearchFieldResultsDecorationStyle(RenderStyle* style, Element*) const
258 {
259     // Scale the decoration size based on the font size
260     float fontScale = style->fontSize() / defaultControlFontPixelSize;
261     int magnifierSize = lroundf(std::min(std::max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale),
262                                          maxSearchFieldResultsDecorationSize));
263     style->setWidth(Length(magnifierSize, Fixed));
264     style->setHeight(Length(magnifierSize, Fixed));
265 }
266
267 bool RenderThemeChromiumSkia::paintSearchFieldResultsDecoration(RenderObject* magnifierObject, const PaintInfo& paintInfo, const IntRect& r)
268 {
269     // Get the renderer of <input> element.
270     if (!magnifierObject->node())
271         return false;
272     Node* input = magnifierObject->node()->shadowHost();
273     RenderObject* baseRenderer = input ? input->renderer() : magnifierObject;
274     if (!baseRenderer->isBox())
275         return false;
276     RenderBox* inputRenderBox = toRenderBox(baseRenderer);
277     LayoutRect inputContentBox = inputRenderBox->contentBoxRect();
278
279     // Make sure the scaled decoration stays square and will fit in its parent's box.
280     LayoutUnit magnifierSize = std::min(inputContentBox.width(), std::min<LayoutUnit>(inputContentBox.height(), r.height()));
281     // Calculate decoration's coordinates relative to the input element.
282     // Center the decoration vertically.  Round up though, so if it has to be one pixel off-center, it will
283     // be one pixel closer to the bottom of the field.  This tends to look better with the text.
284     LayoutRect magnifierRect(magnifierObject->offsetFromAncestorContainer(inputRenderBox).width(),
285                              inputContentBox.y() + (inputContentBox.height() - magnifierSize + 1) / 2,
286                              magnifierSize, magnifierSize);
287     IntRect paintingRect = convertToPaintingRect(inputRenderBox, magnifierObject, magnifierRect, r);
288
289     DEFINE_STATIC_REF(Image, magnifierImage, (Image::loadPlatformResource("searchMagnifier")));
290     paintInfo.context->drawImage(magnifierImage, paintingRect);
291     return false;
292 }
293
294 bool RenderThemeChromiumSkia::paintMediaSliderTrack(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
295 {
296     return RenderMediaControls::paintMediaControlsPart(MediaSlider, object, paintInfo, rect);
297 }
298
299 bool RenderThemeChromiumSkia::paintMediaVolumeSliderTrack(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
300 {
301     return RenderMediaControls::paintMediaControlsPart(MediaVolumeSlider, object, paintInfo, rect);
302 }
303
304 void RenderThemeChromiumSkia::adjustSliderThumbSize(RenderStyle* style, Element*) const
305 {
306     RenderMediaControls::adjustMediaSliderThumbSize(style);
307 }
308
309 bool RenderThemeChromiumSkia::paintMediaSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
310 {
311     return RenderMediaControls::paintMediaControlsPart(MediaSliderThumb, object, paintInfo, rect);
312 }
313
314 bool RenderThemeChromiumSkia::paintMediaToggleClosedCaptionsButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
315 {
316     return RenderMediaControls::paintMediaControlsPart(MediaShowClosedCaptionsButton, o, paintInfo, r);
317 }
318
319 bool RenderThemeChromiumSkia::paintMediaCastButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
320 {
321     return RenderMediaControls::paintMediaControlsPart(MediaCastOffButton, o, paintInfo, r);
322 }
323
324 bool RenderThemeChromiumSkia::paintMediaVolumeSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
325 {
326     return RenderMediaControls::paintMediaControlsPart(MediaVolumeSliderThumb, object, paintInfo, rect);
327 }
328
329 bool RenderThemeChromiumSkia::paintMediaPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
330 {
331     return RenderMediaControls::paintMediaControlsPart(MediaPlayButton, object, paintInfo, rect);
332 }
333
334 bool RenderThemeChromiumSkia::paintMediaOverlayPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
335 {
336     return RenderMediaControls::paintMediaControlsPart(MediaOverlayPlayButton, object, paintInfo, rect);
337 }
338
339 bool RenderThemeChromiumSkia::paintMediaMuteButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
340 {
341     return RenderMediaControls::paintMediaControlsPart(MediaMuteButton, object, paintInfo, rect);
342 }
343
344 String RenderThemeChromiumSkia::formatMediaControlsTime(float time) const
345 {
346     return RenderMediaControls::formatMediaControlsTime(time);
347 }
348
349 String RenderThemeChromiumSkia::formatMediaControlsCurrentTime(float currentTime, float duration) const
350 {
351     return RenderMediaControls::formatMediaControlsCurrentTime(currentTime, duration);
352 }
353
354 bool RenderThemeChromiumSkia::paintMediaFullscreenButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
355 {
356     return RenderMediaControls::paintMediaControlsPart(MediaEnterFullscreenButton, object, paintInfo, rect);
357 }
358
359 void RenderThemeChromiumSkia::adjustMenuListStyle(RenderStyle* style, Element*) const
360 {
361     // Height is locked to auto on all browsers.
362     style->setLineHeight(RenderStyle::initialLineHeight());
363 }
364
365 void RenderThemeChromiumSkia::adjustMenuListButtonStyle(RenderStyle* style, Element* e) const
366 {
367     adjustMenuListStyle(style, e);
368 }
369
370 // Used to paint styled menulists (i.e. with a non-default border)
371 bool RenderThemeChromiumSkia::paintMenuListButton(RenderObject* o, const PaintInfo& i, const IntRect& rect)
372 {
373     return paintMenuList(o, i, rect);
374 }
375
376 int RenderThemeChromiumSkia::popupInternalPaddingLeft(RenderStyle* style) const
377 {
378     return menuListInternalPadding(style, LeftPadding);
379 }
380
381 int RenderThemeChromiumSkia::popupInternalPaddingRight(RenderStyle* style) const
382 {
383     return menuListInternalPadding(style, RightPadding);
384 }
385
386 int RenderThemeChromiumSkia::popupInternalPaddingTop(RenderStyle* style) const
387 {
388     return menuListInternalPadding(style, TopPadding);
389 }
390
391 int RenderThemeChromiumSkia::popupInternalPaddingBottom(RenderStyle* style) const
392 {
393     return menuListInternalPadding(style, BottomPadding);
394 }
395
396 // static
397 void RenderThemeChromiumSkia::setDefaultFontSize(int fontSize)
398 {
399     RenderThemeChromiumFontProvider::setDefaultFontSize(fontSize);
400 }
401
402 double RenderThemeChromiumSkia::caretBlinkIntervalInternal() const
403 {
404     return RenderTheme::caretBlinkInterval();
405 }
406
407 int RenderThemeChromiumSkia::menuListArrowPadding() const
408 {
409     return ScrollbarTheme::theme()->scrollbarThickness();
410 }
411
412 int RenderThemeChromiumSkia::menuListInternalPadding(RenderStyle* style, int paddingType) const
413 {
414     // This internal padding is in addition to the user-supplied padding.
415     // Matches the FF behavior.
416     int padding = styledMenuListInternalPadding[paddingType];
417
418     // Reserve the space for right arrow here. The rest of the padding is
419     // set by adjustMenuListStyle, since PopMenuWin.cpp uses the padding from
420     // RenderMenuList to lay out the individual items in the popup.
421     // If the MenuList actually has appearance "NoAppearance", then that means
422     // we don't draw a button, so don't reserve space for it.
423     const int barType = style->direction() == LTR ? RightPadding : LeftPadding;
424     if (paddingType == barType && style->appearance() != NoControlPart)
425         padding += menuListArrowPadding();
426
427     return padding;
428 }
429
430 bool RenderThemeChromiumSkia::shouldShowPlaceholderWhenFocused() const
431 {
432     return true;
433 }
434
435 //
436 // Following values are come from default of GTK+
437 //
438 static const int progressActivityBlocks = 5;
439 static const int progressAnimationFrames = 10;
440 static const double progressAnimationInterval = 0.125;
441
442 IntRect RenderThemeChromiumSkia::determinateProgressValueRectFor(RenderProgress* renderProgress, const IntRect& rect) const
443 {
444     int dx = rect.width() * renderProgress->position();
445     return IntRect(rect.x(), rect.y(), dx, rect.height());
446 }
447
448 IntRect RenderThemeChromiumSkia::indeterminateProgressValueRectFor(RenderProgress* renderProgress, const IntRect& rect) const
449 {
450
451     int valueWidth = rect.width() / progressActivityBlocks;
452     int movableWidth = rect.width() - valueWidth;
453     if (movableWidth <= 0)
454         return IntRect();
455
456     double progress = renderProgress->animationProgress();
457     if (progress < 0.5)
458         return IntRect(rect.x() + progress * 2 * movableWidth, rect.y(), valueWidth, rect.height());
459     return IntRect(rect.x() + (1.0 - progress) * 2 * movableWidth, rect.y(), valueWidth, rect.height());
460 }
461
462 double RenderThemeChromiumSkia::animationRepeatIntervalForProgressBar(RenderProgress*) const
463 {
464     return progressAnimationInterval;
465 }
466
467 double RenderThemeChromiumSkia::animationDurationForProgressBar(RenderProgress* renderProgress) const
468 {
469     return progressAnimationInterval * progressAnimationFrames * 2; // "2" for back and forth
470 }
471
472 IntRect RenderThemeChromiumSkia::progressValueRectFor(RenderProgress* renderProgress, const IntRect& rect) const
473 {
474     return renderProgress->isDeterminate() ? determinateProgressValueRectFor(renderProgress, rect) : indeterminateProgressValueRectFor(renderProgress, rect);
475 }
476
477 RenderThemeChromiumSkia::DirectionFlippingScope::DirectionFlippingScope(RenderObject* renderer, const PaintInfo& paintInfo, const IntRect& rect)
478     : m_needsFlipping(!renderer->style()->isLeftToRightDirection())
479     , m_paintInfo(paintInfo)
480 {
481     if (!m_needsFlipping)
482         return;
483     m_paintInfo.context->save();
484     m_paintInfo.context->translate(2 * rect.x() + rect.width(), 0);
485     m_paintInfo.context->scale(-1, 1);
486 }
487
488 RenderThemeChromiumSkia::DirectionFlippingScope::~DirectionFlippingScope()
489 {
490     if (!m_needsFlipping)
491         return;
492     m_paintInfo.context->restore();
493 }
494
495 } // namespace blink