Upstream version 7.36.149.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 "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 WebCore {
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(themeWinUserAgentStyleSheet, sizeof(themeWinUserAgentStyleSheet)) +
74         String(themeChromiumSkiaUserAgentStyleSheet, sizeof(themeChromiumSkiaUserAgentStyleSheet)) +
75         String(themeChromiumUserAgentStyleSheet, sizeof(themeChromiumUserAgentStyleSheet));
76 }
77
78 String RenderThemeChromiumSkia::extraQuirksStyleSheet()
79 {
80     return String(themeWinQuirksUserAgentStyleSheet, sizeof(themeWinQuirksUserAgentStyleSheet));
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 (isRunningLayoutTest())
125         return 0;
126
127     return caretBlinkIntervalInternal();
128 }
129
130 void RenderThemeChromiumSkia::systemFont(CSSValueID valueID, FontDescription& fontDescription) const
131 {
132     RenderThemeChromiumFontProvider::systemFont(valueID, fontDescription);
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::paintMediaVolumeSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
320 {
321     return RenderMediaControls::paintMediaControlsPart(MediaVolumeSliderThumb, object, paintInfo, rect);
322 }
323
324 bool RenderThemeChromiumSkia::paintMediaPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
325 {
326     return RenderMediaControls::paintMediaControlsPart(MediaPlayButton, object, paintInfo, rect);
327 }
328
329 bool RenderThemeChromiumSkia::paintMediaOverlayPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
330 {
331     return RenderMediaControls::paintMediaControlsPart(MediaOverlayPlayButton, object, paintInfo, rect);
332 }
333
334 bool RenderThemeChromiumSkia::paintMediaMuteButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
335 {
336     return RenderMediaControls::paintMediaControlsPart(MediaMuteButton, object, paintInfo, rect);
337 }
338
339 String RenderThemeChromiumSkia::formatMediaControlsTime(float time) const
340 {
341     return RenderMediaControls::formatMediaControlsTime(time);
342 }
343
344 String RenderThemeChromiumSkia::formatMediaControlsCurrentTime(float currentTime, float duration) const
345 {
346     return RenderMediaControls::formatMediaControlsCurrentTime(currentTime, duration);
347 }
348
349 bool RenderThemeChromiumSkia::paintMediaFullscreenButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
350 {
351     return RenderMediaControls::paintMediaControlsPart(MediaEnterFullscreenButton, object, paintInfo, rect);
352 }
353
354 void RenderThemeChromiumSkia::adjustMenuListStyle(RenderStyle* style, WebCore::Element*) const
355 {
356     // Height is locked to auto on all browsers.
357     style->setLineHeight(RenderStyle::initialLineHeight());
358 }
359
360 void RenderThemeChromiumSkia::adjustMenuListButtonStyle(RenderStyle* style, Element* e) const
361 {
362     adjustMenuListStyle(style, e);
363 }
364
365 // Used to paint styled menulists (i.e. with a non-default border)
366 bool RenderThemeChromiumSkia::paintMenuListButton(RenderObject* o, const PaintInfo& i, const IntRect& rect)
367 {
368     return paintMenuList(o, i, rect);
369 }
370
371 int RenderThemeChromiumSkia::popupInternalPaddingLeft(RenderStyle* style) const
372 {
373     return menuListInternalPadding(style, LeftPadding);
374 }
375
376 int RenderThemeChromiumSkia::popupInternalPaddingRight(RenderStyle* style) const
377 {
378     return menuListInternalPadding(style, RightPadding);
379 }
380
381 int RenderThemeChromiumSkia::popupInternalPaddingTop(RenderStyle* style) const
382 {
383     return menuListInternalPadding(style, TopPadding);
384 }
385
386 int RenderThemeChromiumSkia::popupInternalPaddingBottom(RenderStyle* style) const
387 {
388     return menuListInternalPadding(style, BottomPadding);
389 }
390
391 // static
392 void RenderThemeChromiumSkia::setDefaultFontSize(int fontSize)
393 {
394     RenderThemeChromiumFontProvider::setDefaultFontSize(fontSize);
395 }
396
397 double RenderThemeChromiumSkia::caretBlinkIntervalInternal() const
398 {
399     return RenderTheme::caretBlinkInterval();
400 }
401
402 int RenderThemeChromiumSkia::menuListArrowPadding() const
403 {
404     return ScrollbarTheme::theme()->scrollbarThickness();
405 }
406
407 int RenderThemeChromiumSkia::menuListInternalPadding(RenderStyle* style, int paddingType) const
408 {
409     // This internal padding is in addition to the user-supplied padding.
410     // Matches the FF behavior.
411     int padding = styledMenuListInternalPadding[paddingType];
412
413     // Reserve the space for right arrow here. The rest of the padding is
414     // set by adjustMenuListStyle, since PopMenuWin.cpp uses the padding from
415     // RenderMenuList to lay out the individual items in the popup.
416     // If the MenuList actually has appearance "NoAppearance", then that means
417     // we don't draw a button, so don't reserve space for it.
418     const int barType = style->direction() == LTR ? RightPadding : LeftPadding;
419     if (paddingType == barType && style->appearance() != NoControlPart)
420         padding += menuListArrowPadding();
421
422     return padding;
423 }
424
425 bool RenderThemeChromiumSkia::shouldShowPlaceholderWhenFocused() const
426 {
427     return true;
428 }
429
430 //
431 // Following values are come from default of GTK+
432 //
433 static const int progressActivityBlocks = 5;
434 static const int progressAnimationFrames = 10;
435 static const double progressAnimationInterval = 0.125;
436
437 IntRect RenderThemeChromiumSkia::determinateProgressValueRectFor(RenderProgress* renderProgress, const IntRect& rect) const
438 {
439     int dx = rect.width() * renderProgress->position();
440     return IntRect(rect.x(), rect.y(), dx, rect.height());
441 }
442
443 IntRect RenderThemeChromiumSkia::indeterminateProgressValueRectFor(RenderProgress* renderProgress, const IntRect& rect) const
444 {
445
446     int valueWidth = rect.width() / progressActivityBlocks;
447     int movableWidth = rect.width() - valueWidth;
448     if (movableWidth <= 0)
449         return IntRect();
450
451     double progress = renderProgress->animationProgress();
452     if (progress < 0.5)
453         return IntRect(rect.x() + progress * 2 * movableWidth, rect.y(), valueWidth, rect.height());
454     return IntRect(rect.x() + (1.0 - progress) * 2 * movableWidth, rect.y(), valueWidth, rect.height());
455 }
456
457 double RenderThemeChromiumSkia::animationRepeatIntervalForProgressBar(RenderProgress*) const
458 {
459     return progressAnimationInterval;
460 }
461
462 double RenderThemeChromiumSkia::animationDurationForProgressBar(RenderProgress* renderProgress) const
463 {
464     return progressAnimationInterval * progressAnimationFrames * 2; // "2" for back and forth
465 }
466
467 IntRect RenderThemeChromiumSkia::progressValueRectFor(RenderProgress* renderProgress, const IntRect& rect) const
468 {
469     return renderProgress->isDeterminate() ? determinateProgressValueRectFor(renderProgress, rect) : indeterminateProgressValueRectFor(renderProgress, rect);
470 }
471
472 RenderThemeChromiumSkia::DirectionFlippingScope::DirectionFlippingScope(RenderObject* renderer, const PaintInfo& paintInfo, const IntRect& rect)
473     : m_needsFlipping(!renderer->style()->isLeftToRightDirection())
474     , m_paintInfo(paintInfo)
475 {
476     if (!m_needsFlipping)
477         return;
478     m_paintInfo.context->save();
479     m_paintInfo.context->translate(2 * rect.x() + rect.width(), 0);
480     m_paintInfo.context->scale(FloatSize(-1, 1));
481 }
482
483 RenderThemeChromiumSkia::DirectionFlippingScope::~DirectionFlippingScope()
484 {
485     if (!m_needsFlipping)
486         return;
487     m_paintInfo.context->restore();
488 }
489
490 } // namespace WebCore