bb60c1f771b504d62922140800e655a1ba1637e5
[WebKit-https.git] / Source / WebCore / 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 "RenderThemeChromiumSkia.h"
26
27 #include "ChromiumBridge.h"
28 #include "CSSValueKeywords.h"
29 #include "CurrentTime.h"
30 #include "GraphicsContext.h"
31 #include "HTMLMediaElement.h"
32 #include "HTMLNames.h"
33 #include "Image.h"
34 #include "MediaControlElements.h"
35 #include "PaintInfo.h"
36 #include "PlatformContextSkia.h"
37 #include "RenderBox.h"
38 #include "RenderMediaControlsChromium.h"
39 #include "RenderObject.h"
40 #include "RenderProgress.h"
41 #include "RenderSlider.h"
42 #include "ScrollbarTheme.h"
43 #include "TimeRanges.h"
44 #include "TransformationMatrix.h"
45 #include "UserAgentStyleSheets.h"
46
47 #include "SkShader.h"
48 #include "SkGradientShader.h"
49
50 namespace WebCore {
51
52 enum PaddingType {
53     TopPadding,
54     RightPadding,
55     BottomPadding,
56     LeftPadding
57 };
58
59 static const int styledMenuListInternalPadding[4] = { 1, 4, 1, 4 };
60
61 // These values all match Safari/Win.
62 static const float defaultControlFontPixelSize = 13;
63 static const float defaultCancelButtonSize = 9;
64 static const float minCancelButtonSize = 5;
65 static const float maxCancelButtonSize = 21;
66 static const float defaultSearchFieldResultsDecorationSize = 13;
67 static const float minSearchFieldResultsDecorationSize = 9;
68 static const float maxSearchFieldResultsDecorationSize = 30;
69 static const float defaultSearchFieldResultsButtonWidth = 18;
70
71 static void setSizeIfAuto(RenderStyle* style, const IntSize& size)
72 {
73     if (style->width().isIntrinsicOrAuto())
74         style->setWidth(Length(size.width(), Fixed));
75     if (style->height().isAuto())
76         style->setHeight(Length(size.height(), Fixed));
77 }
78
79 static void drawVertLine(SkCanvas* canvas, int x, int y1, int y2, const SkPaint& paint)
80 {
81     SkIRect skrect;
82     skrect.set(x, y1, x + 1, y2 + 1);
83     canvas->drawIRect(skrect, paint);
84 }
85
86 static void drawHorizLine(SkCanvas* canvas, int x1, int x2, int y, const SkPaint& paint)
87 {
88     SkIRect skrect;
89     skrect.set(x1, y, x2 + 1, y + 1);
90     canvas->drawIRect(skrect, paint);
91 }
92
93 static void drawBox(SkCanvas* canvas, const IntRect& rect, const SkPaint& paint)
94 {
95     const int right = rect.x() + rect.width() - 1;
96     const int bottom = rect.y() + rect.height() - 1;
97     drawHorizLine(canvas, rect.x(), right, rect.y(), paint);
98     drawVertLine(canvas, right, rect.y(), bottom, paint);
99     drawHorizLine(canvas, rect.x(), right, bottom, paint);
100     drawVertLine(canvas, rect.x(), rect.y(), bottom, paint);
101 }
102
103 // We aim to match IE here.
104 // -IE uses a font based on the encoding as the default font for form controls.
105 // -Gecko uses MS Shell Dlg (actually calls GetStockObject(DEFAULT_GUI_FONT),
106 // which returns MS Shell Dlg)
107 // -Safari uses Lucida Grande.
108 //
109 // FIXME: The only case where we know we don't match IE is for ANSI encodings.
110 // IE uses MS Shell Dlg there, which we render incorrectly at certain pixel
111 // sizes (e.g. 15px). So, for now we just use Arial.
112 const String& RenderThemeChromiumSkia::defaultGUIFont()
113 {
114     DEFINE_STATIC_LOCAL(String, fontFace, ("Arial"));
115     return fontFace;
116 }
117
118 float RenderThemeChromiumSkia::defaultFontSize = 16.0;
119
120 RenderThemeChromiumSkia::RenderThemeChromiumSkia()
121 {
122 }
123
124 RenderThemeChromiumSkia::~RenderThemeChromiumSkia()
125 {
126 }
127
128 // Use the Windows style sheets to match their metrics.
129 String RenderThemeChromiumSkia::extraDefaultStyleSheet()
130 {
131     return String(themeWinUserAgentStyleSheet, sizeof(themeWinUserAgentStyleSheet)) +
132            String(themeChromiumSkiaUserAgentStyleSheet, sizeof(themeChromiumSkiaUserAgentStyleSheet));
133 }
134
135 String RenderThemeChromiumSkia::extraQuirksStyleSheet()
136 {
137     return String(themeWinQuirksUserAgentStyleSheet, sizeof(themeWinQuirksUserAgentStyleSheet));
138 }
139
140 #if ENABLE(VIDEO)
141 String RenderThemeChromiumSkia::extraMediaControlsStyleSheet()
142 {
143     return String(mediaControlsChromiumUserAgentStyleSheet, sizeof(mediaControlsChromiumUserAgentStyleSheet));
144 }
145 #endif
146
147 bool RenderThemeChromiumSkia::supportsHover(const RenderStyle* style) const
148 {
149     return true;
150 }
151
152 bool RenderThemeChromiumSkia::supportsFocusRing(const RenderStyle* style) const
153 {
154     // This causes WebKit to draw the focus rings for us.
155     return false;
156 }
157
158 Color RenderThemeChromiumSkia::platformActiveSelectionBackgroundColor() const
159 {
160     return Color(0x1e, 0x90, 0xff);
161 }
162
163 Color RenderThemeChromiumSkia::platformInactiveSelectionBackgroundColor() const
164 {
165     return Color(0xc8, 0xc8, 0xc8);
166 }
167
168 Color RenderThemeChromiumSkia::platformActiveSelectionForegroundColor() const
169 {
170     return Color::black;
171 }
172
173 Color RenderThemeChromiumSkia::platformInactiveSelectionForegroundColor() const
174 {
175     return Color(0x32, 0x32, 0x32);
176 }
177
178 Color RenderThemeChromiumSkia::platformFocusRingColor() const
179 {
180     static Color focusRingColor(229, 151, 0, 255);
181     return focusRingColor;
182 }
183
184 double RenderThemeChromiumSkia::caretBlinkInterval() const
185 {
186     // Disable the blinking caret in layout test mode, as it introduces
187     // a race condition for the pixel tests. http://b/1198440
188     if (ChromiumBridge::layoutTestMode())
189         return 0;
190
191     return caretBlinkIntervalInternal();
192 }
193
194 void RenderThemeChromiumSkia::systemFont(int propId, FontDescription& fontDescription) const
195 {
196     float fontSize = defaultFontSize;
197
198     switch (propId) {
199     case CSSValueWebkitMiniControl:
200     case CSSValueWebkitSmallControl:
201     case CSSValueWebkitControl:
202         // Why 2 points smaller? Because that's what Gecko does. Note that we
203         // are assuming a 96dpi screen, which is the default that we use on
204         // Windows.
205         static const float pointsPerInch = 72.0f;
206         static const float pixelsPerInch = 96.0f;
207         fontSize -= (2.0f / pointsPerInch) * pixelsPerInch;
208         break;
209     }
210
211     fontDescription.firstFamily().setFamily(defaultGUIFont());
212     fontDescription.setSpecifiedSize(fontSize);
213     fontDescription.setIsAbsoluteSize(true);
214     fontDescription.setGenericFamily(FontDescription::NoFamily);
215     fontDescription.setWeight(FontWeightNormal);
216     fontDescription.setItalic(false);
217 }
218
219 int RenderThemeChromiumSkia::minimumMenuListSize(RenderStyle* style) const
220 {
221     return 0;
222 }
223
224 // These are the default dimensions of radio buttons and checkboxes.
225 static const int widgetStandardWidth = 13;
226 static const int widgetStandardHeight = 13;
227
228 // Return a rectangle that has the same center point as |original|, but with a
229 // size capped at |width| by |height|.
230 IntRect center(const IntRect& original, int width, int height)
231 {
232     width = std::min(original.width(), width);
233     height = std::min(original.height(), height);
234     int x = original.x() + (original.width() - width) / 2;
235     int y = original.y() + (original.height() - height) / 2;
236
237     return IntRect(x, y, width, height);
238 }
239
240 bool RenderThemeChromiumSkia::paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& rect)
241 {
242     static Image* const checkedImage = Image::loadPlatformResource("linuxCheckboxOn").releaseRef();
243     static Image* const uncheckedImage = Image::loadPlatformResource("linuxCheckboxOff").releaseRef();
244     static Image* const indeterminateImage = Image::loadPlatformResource("linuxCheckboxIndeterminate").releaseRef();
245     static Image* const disabledCheckedImage = Image::loadPlatformResource("linuxCheckboxDisabledOn").releaseRef();
246     static Image* const disabledUncheckedImage = Image::loadPlatformResource("linuxCheckboxDisabledOff").releaseRef();
247     static Image* const disabledIndeterminateImage = Image::loadPlatformResource("linuxCheckboxDisabledIndeterminate").releaseRef();
248
249     Image* image;
250
251     if (isIndeterminate(o))
252         image = isEnabled(o) ? indeterminateImage : disabledIndeterminateImage;
253     else if (isChecked(o))
254         image = isEnabled(o) ? checkedImage : disabledCheckedImage;
255     else
256         image = isEnabled(o) ? uncheckedImage : disabledUncheckedImage;
257
258     i.context->drawImage(image, o->style()->colorSpace(), center(rect, widgetStandardHeight, widgetStandardWidth));
259     return false;
260 }
261
262 void RenderThemeChromiumSkia::setCheckboxSize(RenderStyle* style) const
263 {
264     // If the width and height are both specified, then we have nothing to do.
265     if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
266         return;
267
268     // FIXME:  A hard-coded size of 13 is used.  This is wrong but necessary
269     // for now.  It matches Firefox.  At different DPI settings on Windows,
270     // querying the theme gives you a larger size that accounts for the higher
271     // DPI.  Until our entire engine honors a DPI setting other than 96, we
272     // can't rely on the theme's metrics.
273     const IntSize size(widgetStandardHeight, widgetStandardWidth);
274     setSizeIfAuto(style, size);
275 }
276
277 bool RenderThemeChromiumSkia::paintRadio(RenderObject* o, const PaintInfo& i, const IntRect& rect)
278 {
279     static Image* const checkedImage = Image::loadPlatformResource("linuxRadioOn").releaseRef();
280     static Image* const uncheckedImage = Image::loadPlatformResource("linuxRadioOff").releaseRef();
281     static Image* const disabledCheckedImage = Image::loadPlatformResource("linuxRadioDisabledOn").releaseRef();
282     static Image* const disabledUncheckedImage = Image::loadPlatformResource("linuxRadioDisabledOff").releaseRef();
283
284     Image* image;
285     if (this->isEnabled(o))
286         image = this->isChecked(o) ? checkedImage : uncheckedImage;
287     else
288         image = this->isChecked(o) ? disabledCheckedImage : disabledUncheckedImage;
289
290     i.context->drawImage(image, o->style()->colorSpace(), center(rect, widgetStandardHeight, widgetStandardWidth));
291     return false;
292 }
293
294 void RenderThemeChromiumSkia::setRadioSize(RenderStyle* style) const
295 {
296     // Use same sizing for radio box as checkbox.
297     setCheckboxSize(style);
298 }
299
300 static SkColor brightenColor(double h, double s, double l, float brightenAmount)
301 {
302     l += brightenAmount;
303     if (l > 1.0)
304         l = 1.0;
305     if (l < 0.0)
306         l = 0.0;
307
308     return makeRGBAFromHSLA(h, s, l, 1.0);
309 }
310
311 static void paintButtonLike(RenderTheme* theme, RenderObject* o, const PaintInfo& i, const IntRect& rect)
312 {
313     SkCanvas* const canvas = i.context->platformContext()->canvas();
314     SkPaint paint;
315     SkRect skrect;
316     const int right = rect.x() + rect.width();
317     const int bottom = rect.y() + rect.height();
318     SkColor baseColor = SkColorSetARGB(0xff, 0xdd, 0xdd, 0xdd);
319     if (o->hasBackground())
320         baseColor = o->style()->visitedDependentColor(CSSPropertyBackgroundColor).rgb();
321     double h, s, l;
322     Color(baseColor).getHSL(h, s, l);
323     // Our standard gradient is from 0xdd to 0xf8. This is the amount of
324     // increased luminance between those values.
325     SkColor lightColor(brightenColor(h, s, l, 0.105));
326
327     // If the button is too small, fallback to drawing a single, solid color
328     if (rect.width() < 5 || rect.height() < 5) {
329         paint.setColor(baseColor);
330         skrect.set(rect.x(), rect.y(), right, bottom);
331         canvas->drawRect(skrect, paint);
332         return;
333     }
334
335     const int borderAlpha = theme->isHovered(o) ? 0x80 : 0x55;
336     paint.setARGB(borderAlpha, 0, 0, 0);
337     canvas->drawLine(rect.x() + 1, rect.y(), right - 1, rect.y(), paint);
338     canvas->drawLine(right - 1, rect.y() + 1, right - 1, bottom - 1, paint);
339     canvas->drawLine(rect.x() + 1, bottom - 1, right - 1, bottom - 1, paint);
340     canvas->drawLine(rect.x(), rect.y() + 1, rect.x(), bottom - 1, paint);
341
342     paint.setColor(SK_ColorBLACK);
343     SkPoint p[2];
344     const int lightEnd = theme->isPressed(o) ? 1 : 0;
345     const int darkEnd = !lightEnd;
346     p[lightEnd].set(SkIntToScalar(rect.x()), SkIntToScalar(rect.y()));
347     p[darkEnd].set(SkIntToScalar(rect.x()), SkIntToScalar(bottom - 1));
348     SkColor colors[2];
349     colors[0] = lightColor;
350     colors[1] = baseColor;
351
352     SkShader* shader = SkGradientShader::CreateLinear(
353         p, colors, NULL, 2, SkShader::kClamp_TileMode, NULL);
354     paint.setStyle(SkPaint::kFill_Style);
355     paint.setShader(shader);
356     shader->unref();
357
358     skrect.set(rect.x() + 1, rect.y() + 1, right - 1, bottom - 1);
359     canvas->drawRect(skrect, paint);
360
361     paint.setShader(NULL);
362     paint.setColor(brightenColor(h, s, l, -0.0588));
363     canvas->drawPoint(rect.x() + 1, rect.y() + 1, paint);
364     canvas->drawPoint(right - 2, rect.y() + 1, paint);
365     canvas->drawPoint(rect.x() + 1, bottom - 2, paint);
366     canvas->drawPoint(right - 2, bottom - 2, paint);
367 }
368
369 bool RenderThemeChromiumSkia::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& rect)
370 {
371     paintButtonLike(this, o, i, rect);
372     return false;
373 }
374
375 void RenderThemeChromiumSkia::adjustButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
376 {
377     if (style->appearance() == PushButtonPart) {
378         // Ignore line-height.
379         style->setLineHeight(RenderStyle::initialLineHeight());
380     }
381 }
382
383
384 bool RenderThemeChromiumSkia::paintTextField(RenderObject* o, const PaintInfo& i, const IntRect& rect)
385 {
386     return true;
387 }
388
389 bool RenderThemeChromiumSkia::paintTextArea(RenderObject* o, const PaintInfo& i, const IntRect& r)
390 {
391     return paintTextField(o, i, r);
392 }
393
394 void RenderThemeChromiumSkia::adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
395 {
396      // Ignore line-height.
397      style->setLineHeight(RenderStyle::initialLineHeight());
398 }
399
400 bool RenderThemeChromiumSkia::paintSearchField(RenderObject* o, const PaintInfo& i, const IntRect& r)
401 {
402     return paintTextField(o, i, r);
403 }
404
405 void RenderThemeChromiumSkia::adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
406 {
407     // Scale the button size based on the font size
408     float fontScale = style->fontSize() / defaultControlFontPixelSize;
409     int cancelButtonSize = lroundf(std::min(std::max(minCancelButtonSize, defaultCancelButtonSize * fontScale), maxCancelButtonSize));
410     style->setWidth(Length(cancelButtonSize, Fixed));
411     style->setHeight(Length(cancelButtonSize, Fixed));
412 }
413
414 IntRect RenderThemeChromiumSkia::convertToPaintingRect(RenderObject* inputRenderer, const RenderObject* partRenderer, IntRect partRect, const IntRect& localOffset) const
415 {
416     // Compute an offset between the part renderer and the input renderer.
417     IntSize offsetFromInputRenderer = -(partRenderer->offsetFromAncestorContainer(inputRenderer));
418     // Move the rect into partRenderer's coords.
419     partRect.move(offsetFromInputRenderer);
420     // Account for the local drawing offset.
421     partRect.move(localOffset.x(), localOffset.y());
422
423     return partRect;
424 }
425
426 bool RenderThemeChromiumSkia::paintSearchFieldCancelButton(RenderObject* cancelButtonObject, const PaintInfo& paintInfo, const IntRect& r)
427 {
428     // Get the renderer of <input> element.
429     Node* input = cancelButtonObject->node()->shadowAncestorNode();
430     if (!input->renderer()->isBox())
431         return false;
432     RenderBox* inputRenderBox = toRenderBox(input->renderer());
433     IntRect inputContentBox = inputRenderBox->contentBoxRect();
434
435     // Make sure the scaled button stays square and will fit in its parent's box.
436     int cancelButtonSize = std::min(inputContentBox.width(), std::min(inputContentBox.height(), r.height()));
437     // Calculate cancel button's coordinates relative to the input element.
438     // Center the button vertically.  Round up though, so if it has to be one pixel off-center, it will
439     // be one pixel closer to the bottom of the field.  This tends to look better with the text.
440     IntRect cancelButtonRect(cancelButtonObject->offsetFromAncestorContainer(inputRenderBox).width(),
441                              inputContentBox.y() + (inputContentBox.height() - cancelButtonSize + 1) / 2,
442                              cancelButtonSize, cancelButtonSize);
443     IntRect paintingRect = convertToPaintingRect(inputRenderBox, cancelButtonObject, cancelButtonRect, r);
444
445     static Image* cancelImage = Image::loadPlatformResource("searchCancel").releaseRef();
446     static Image* cancelPressedImage = Image::loadPlatformResource("searchCancelPressed").releaseRef();
447     paintInfo.context->drawImage(isPressed(cancelButtonObject) ? cancelPressedImage : cancelImage,
448                                  cancelButtonObject->style()->colorSpace(), paintingRect);
449     return false;
450 }
451
452 void RenderThemeChromiumSkia::adjustSearchFieldDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
453 {
454     IntSize emptySize(1, 11);
455     style->setWidth(Length(emptySize.width(), Fixed));
456     style->setHeight(Length(emptySize.height(), Fixed));
457 }
458
459 void RenderThemeChromiumSkia::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
460 {
461     // Scale the decoration size based on the font size
462     float fontScale = style->fontSize() / defaultControlFontPixelSize;
463     int magnifierSize = lroundf(std::min(std::max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale),
464                                          maxSearchFieldResultsDecorationSize));
465     style->setWidth(Length(magnifierSize, Fixed));
466     style->setHeight(Length(magnifierSize, Fixed));
467 }
468
469 bool RenderThemeChromiumSkia::paintSearchFieldResultsDecoration(RenderObject* magnifierObject, const PaintInfo& paintInfo, const IntRect& r)
470 {
471     // Get the renderer of <input> element.
472     Node* input = magnifierObject->node()->shadowAncestorNode();
473     if (!input->renderer()->isBox())
474         return false;
475     RenderBox* inputRenderBox = toRenderBox(input->renderer());
476     IntRect inputContentBox = inputRenderBox->contentBoxRect();
477
478     // Make sure the scaled decoration stays square and will fit in its parent's box.
479     int magnifierSize = std::min(inputContentBox.width(), std::min(inputContentBox.height(), r.height()));
480     // Calculate decoration's coordinates relative to the input element.
481     // Center the decoration vertically.  Round up though, so if it has to be one pixel off-center, it will
482     // be one pixel closer to the bottom of the field.  This tends to look better with the text.
483     IntRect magnifierRect(magnifierObject->offsetFromAncestorContainer(inputRenderBox).width(),
484                           inputContentBox.y() + (inputContentBox.height() - magnifierSize + 1) / 2,
485                           magnifierSize, magnifierSize);
486     IntRect paintingRect = convertToPaintingRect(inputRenderBox, magnifierObject, magnifierRect, r);
487
488     static Image* magnifierImage = Image::loadPlatformResource("searchMagnifier").releaseRef();
489     paintInfo.context->drawImage(magnifierImage, magnifierObject->style()->colorSpace(), paintingRect);
490     return false;
491 }
492
493 void RenderThemeChromiumSkia::adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
494 {
495     // Scale the button size based on the font size
496     float fontScale = style->fontSize() / defaultControlFontPixelSize;
497     int magnifierHeight = lroundf(std::min(std::max(minSearchFieldResultsDecorationSize, defaultSearchFieldResultsDecorationSize * fontScale),
498                                            maxSearchFieldResultsDecorationSize));
499     int magnifierWidth = lroundf(magnifierHeight * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize);
500     style->setWidth(Length(magnifierWidth, Fixed));
501     style->setHeight(Length(magnifierHeight, Fixed));
502 }
503
504 bool RenderThemeChromiumSkia::paintSearchFieldResultsButton(RenderObject* magnifierObject, const PaintInfo& paintInfo, const IntRect& r)
505 {
506     // Get the renderer of <input> element.
507     Node* input = magnifierObject->node()->shadowAncestorNode();
508     if (!input->renderer()->isBox())
509         return false;
510     RenderBox* inputRenderBox = toRenderBox(input->renderer());
511     IntRect inputContentBox = inputRenderBox->contentBoxRect();
512
513     // Make sure the scaled decoration will fit in its parent's box.
514     int magnifierHeight = std::min(inputContentBox.height(), r.height());
515     int magnifierWidth = std::min(inputContentBox.width(), static_cast<int>(magnifierHeight * defaultSearchFieldResultsButtonWidth / defaultSearchFieldResultsDecorationSize));
516     IntRect magnifierRect(magnifierObject->offsetFromAncestorContainer(inputRenderBox).width(),
517                           inputContentBox.y() + (inputContentBox.height() - magnifierHeight + 1) / 2,
518                           magnifierWidth, magnifierHeight);
519     IntRect paintingRect = convertToPaintingRect(inputRenderBox, magnifierObject, magnifierRect, r);
520
521     static Image* magnifierImage = Image::loadPlatformResource("searchMagnifierResults").releaseRef();
522     paintInfo.context->drawImage(magnifierImage, magnifierObject->style()->colorSpace(), paintingRect);
523     return false;
524 }
525
526 bool RenderThemeChromiumSkia::paintMediaControlsBackground(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
527 {
528 #if ENABLE(VIDEO)
529     return RenderMediaControlsChromium::paintMediaControlsPart(MediaTimelineContainer, object, paintInfo, rect);
530 #else
531     UNUSED_PARAM(object);
532     UNUSED_PARAM(paintInfo);
533     UNUSED_PARAM(rect);
534     return false;
535 #endif
536 }
537
538 bool RenderThemeChromiumSkia::paintMediaSliderTrack(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
539 {
540 #if ENABLE(VIDEO)
541     return RenderMediaControlsChromium::paintMediaControlsPart(MediaSlider, object, paintInfo, rect);
542 #else
543     UNUSED_PARAM(object);
544     UNUSED_PARAM(paintInfo);
545     UNUSED_PARAM(rect);
546     return false;
547 #endif
548 }
549
550 bool RenderThemeChromiumSkia::paintMediaVolumeSliderTrack(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
551 {
552 #if ENABLE(VIDEO)
553     return RenderMediaControlsChromium::paintMediaControlsPart(MediaVolumeSlider, object, paintInfo, rect);
554 #else
555     UNUSED_PARAM(object);
556     UNUSED_PARAM(paintInfo);
557     UNUSED_PARAM(rect);
558     return false;
559 #endif
560 }
561
562 void RenderThemeChromiumSkia::adjustSliderThumbSize(RenderObject* object) const
563 {
564 #if ENABLE(VIDEO)
565     RenderMediaControlsChromium::adjustMediaSliderThumbSize(object);
566 #else
567     UNUSED_PARAM(object);
568 #endif
569 }
570
571 bool RenderThemeChromiumSkia::paintMediaSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
572 {
573 #if ENABLE(VIDEO)
574     return RenderMediaControlsChromium::paintMediaControlsPart(MediaSliderThumb, object, paintInfo, rect);
575 #else
576     UNUSED_PARAM(object);
577     UNUSED_PARAM(paintInfo);
578     UNUSED_PARAM(rect);
579     return false;
580 #endif
581 }
582
583 bool RenderThemeChromiumSkia::paintMediaVolumeSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
584 {
585 #if ENABLE(VIDEO)
586     return RenderMediaControlsChromium::paintMediaControlsPart(MediaVolumeSliderThumb, object, paintInfo, rect);
587 #else
588     UNUSED_PARAM(object);
589     UNUSED_PARAM(paintInfo);
590     UNUSED_PARAM(rect);
591     return false;
592 #endif
593 }
594
595 bool RenderThemeChromiumSkia::paintMediaPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
596 {
597 #if ENABLE(VIDEO)
598     return RenderMediaControlsChromium::paintMediaControlsPart(MediaPlayButton, object, paintInfo, rect);
599 #else
600     UNUSED_PARAM(object);
601     UNUSED_PARAM(paintInfo);
602     UNUSED_PARAM(rect);
603     return false;
604 #endif
605 }
606
607 bool RenderThemeChromiumSkia::paintMediaMuteButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
608 {
609 #if ENABLE(VIDEO)
610     return RenderMediaControlsChromium::paintMediaControlsPart(MediaMuteButton, object, paintInfo, rect);
611 #else
612     UNUSED_PARAM(object);
613     UNUSED_PARAM(paintInfo);
614     UNUSED_PARAM(rect);
615     return false;
616 #endif
617 }
618
619 void RenderThemeChromiumSkia::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const
620 {
621     // Height is locked to auto on all browsers.
622     style->setLineHeight(RenderStyle::initialLineHeight());
623 }
624
625 bool RenderThemeChromiumSkia::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& rect)
626 {
627     SkCanvas* const canvas = i.context->platformContext()->canvas();
628     const int right = rect.x() + rect.width();
629     const int middle = rect.y() + rect.height() / 2;
630
631     paintButtonLike(this, o, i, rect);
632
633     SkPaint paint;
634     paint.setColor(SK_ColorBLACK);
635     paint.setAntiAlias(true);
636     paint.setStyle(SkPaint::kFill_Style);
637
638     int arrowXPosition = (o->style()->direction() == RTL) ? rect.x() + 7 : right - 13;
639     SkPath path;
640     path.moveTo(arrowXPosition, middle - 3);
641     path.rLineTo(6, 0);
642     path.rLineTo(-3, 6);
643     path.close();
644     canvas->drawPath(path, paint);
645
646     return false;
647 }
648
649 void RenderThemeChromiumSkia::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
650 {
651     adjustMenuListStyle(selector, style, e);
652 }
653
654 // Used to paint styled menulists (i.e. with a non-default border)
655 bool RenderThemeChromiumSkia::paintMenuListButton(RenderObject* o, const PaintInfo& i, const IntRect& rect)
656 {
657     return paintMenuList(o, i, rect);
658 }
659
660 bool RenderThemeChromiumSkia::paintSliderTrack(RenderObject*, const PaintInfo& i, const IntRect& rect)
661 {
662     // Just paint a grey box for now (matches the color of a scrollbar background.
663     SkCanvas* const canvas = i.context->platformContext()->canvas();
664     int verticalCenter = rect.y() + rect.height() / 2;
665     int top = std::max(rect.y(), verticalCenter - 2);
666     int bottom = std::min(rect.y() + rect.height(), verticalCenter + 2);
667
668     SkPaint paint;
669     const SkColor grey = SkColorSetARGB(0xff, 0xe3, 0xdd, 0xd8);
670     paint.setColor(grey);
671
672     SkRect skrect;
673     skrect.set(rect.x(), top, rect.x() + rect.width(), bottom);
674     canvas->drawRect(skrect, paint);
675
676     return false;
677 }
678
679 bool RenderThemeChromiumSkia::paintSliderThumb(RenderObject* o, const PaintInfo& i, const IntRect& rect)
680 {
681     // Make a thumb similar to the scrollbar thumb.
682     const bool hovered = isHovered(o) || toRenderSlider(o->parent())->inDragMode();
683     const int midx = rect.x() + rect.width() / 2;
684     const int midy = rect.y() + rect.height() / 2;
685     const bool vertical = (o->style()->appearance() == SliderThumbVerticalPart);
686     SkCanvas* const canvas = i.context->platformContext()->canvas();
687
688     const SkColor thumbLightGrey = SkColorSetARGB(0xff, 0xf4, 0xf2, 0xef);
689     const SkColor thumbDarkGrey = SkColorSetARGB(0xff, 0xea, 0xe5, 0xe0);
690     SkPaint paint;
691     paint.setColor(hovered ? SK_ColorWHITE : thumbLightGrey);
692
693     SkIRect skrect;
694     if (vertical)
695         skrect.set(rect.x(), rect.y(), midx + 1, rect.bottom());
696     else
697         skrect.set(rect.x(), rect.y(), rect.right(), midy + 1);
698
699     canvas->drawIRect(skrect, paint);
700
701     paint.setColor(hovered ? thumbLightGrey : thumbDarkGrey);
702
703     if (vertical)
704         skrect.set(midx + 1, rect.y(), rect.right(), rect.bottom());
705     else
706         skrect.set(rect.x(), midy + 1, rect.right(), rect.bottom());
707
708     canvas->drawIRect(skrect, paint);
709
710     const SkColor borderDarkGrey = SkColorSetARGB(0xff, 0x9d, 0x96, 0x8e);
711     paint.setColor(borderDarkGrey);
712     drawBox(canvas, rect, paint);
713
714     if (rect.height() > 10 && rect.width() > 10) {
715         drawHorizLine(canvas, midx - 2, midx + 2, midy, paint);
716         drawHorizLine(canvas, midx - 2, midx + 2, midy - 3, paint);
717         drawHorizLine(canvas, midx - 2, midx + 2, midy + 3, paint);
718     }
719
720     return false;
721 }
722
723 int RenderThemeChromiumSkia::popupInternalPaddingLeft(RenderStyle* style) const
724 {
725     return menuListInternalPadding(style, LeftPadding);
726 }
727
728 int RenderThemeChromiumSkia::popupInternalPaddingRight(RenderStyle* style) const
729 {
730     return menuListInternalPadding(style, RightPadding);
731 }
732
733 int RenderThemeChromiumSkia::popupInternalPaddingTop(RenderStyle* style) const
734 {
735     return menuListInternalPadding(style, TopPadding);
736 }
737
738 int RenderThemeChromiumSkia::popupInternalPaddingBottom(RenderStyle* style) const
739 {
740     return menuListInternalPadding(style, BottomPadding);
741 }
742
743 #if ENABLE(VIDEO)
744 bool RenderThemeChromiumSkia::shouldRenderMediaControlPart(ControlPart part, Element* e)
745 {
746     return RenderMediaControlsChromium::shouldRenderMediaControlPart(part, e);
747 }
748 #endif
749
750 // static
751 void RenderThemeChromiumSkia::setDefaultFontSize(int fontSize)
752 {
753     defaultFontSize = static_cast<float>(fontSize);
754 }
755
756 double RenderThemeChromiumSkia::caretBlinkIntervalInternal() const
757 {
758     return RenderTheme::caretBlinkInterval();
759 }
760
761 int RenderThemeChromiumSkia::menuListInternalPadding(RenderStyle* style, int paddingType) const
762 {
763     // This internal padding is in addition to the user-supplied padding.
764     // Matches the FF behavior.
765     int padding = styledMenuListInternalPadding[paddingType];
766
767     // Reserve the space for right arrow here. The rest of the padding is
768     // set by adjustMenuListStyle, since PopMenuWin.cpp uses the padding from
769     // RenderMenuList to lay out the individual items in the popup.
770     // If the MenuList actually has appearance "NoAppearance", then that means
771     // we don't draw a button, so don't reserve space for it.
772     const int barType = style->direction() == LTR ? RightPadding : LeftPadding;
773     if (paddingType == barType && style->appearance() != NoControlPart)
774         padding += ScrollbarTheme::nativeTheme()->scrollbarThickness();
775
776     return padding;
777 }
778
779 #if ENABLE(PROGRESS_TAG)
780
781 //
782 // Following values are come from default of GTK+
783 //
784 static const int progressDeltaPixelsPerSecond = 100;
785 static const int progressActivityBlocks = 5;
786 static const int progressAnimationFrmaes = 10;
787 static const double progressAnimationInterval = 0.125;
788
789 IntRect RenderThemeChromiumSkia::determinateProgressValueRectFor(RenderProgress* renderProgress, const IntRect& rect) const
790 {
791     int dx = rect.width() * renderProgress->position();
792     if (renderProgress->style()->direction() == RTL)
793         return IntRect(rect.x() + rect.width() - dx, rect.y(), dx, rect.height());
794     return IntRect(rect.x(), rect.y(), dx, rect.height());
795 }
796
797 IntRect RenderThemeChromiumSkia::indeterminateProgressValueRectFor(RenderProgress* renderProgress, const IntRect& rect) const
798 {
799
800     int valueWidth = rect.width() / progressActivityBlocks;
801     int movableWidth = rect.width() - valueWidth;
802     if (movableWidth <= 0)
803         return IntRect();
804     
805     double progress = renderProgress->animationProgress();
806     if (progress < 0.5)
807         return IntRect(rect.x() + progress * 2 * movableWidth, rect.y(), valueWidth, rect.height());
808     return IntRect(rect.x() + (1.0 - progress) * 2 * movableWidth, rect.y(), valueWidth, rect.height());
809 }
810
811 double RenderThemeChromiumSkia::animationRepeatIntervalForProgressBar(RenderProgress*) const
812 {
813     return progressAnimationInterval;
814 }
815
816 double RenderThemeChromiumSkia::animationDurationForProgressBar(RenderProgress* renderProgress) const
817 {
818     return progressAnimationInterval * progressAnimationFrmaes * 2; // "2" for back and forth
819 }
820
821 bool RenderThemeChromiumSkia::paintProgressBar(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
822 {
823     static Image* barImage = Image::loadPlatformResource("linuxProgressBar").releaseRef();
824     static Image* valueImage = Image::loadPlatformResource("linuxProgressValue").releaseRef();
825     static Image* leftBorderImage = Image::loadPlatformResource("linuxProgressBorderLeft").releaseRef();
826     static Image* rightBorderImage = Image::loadPlatformResource("linuxProgressBorderRight").releaseRef();
827     ASSERT(barImage->height() == valueImage->height());
828
829     if (!renderObject->isProgress())
830         return true;
831
832     paintInfo.context->platformContext()->setImageResamplingHint(barImage->size(), rect.size());
833
834     RenderProgress* renderProgress = toRenderProgress(renderObject);
835     double tileScale = static_cast<double>(rect.height()) / barImage->height();
836     IntSize barTileSize(static_cast<int>(barImage->width() * tileScale), rect.height());
837     ColorSpace colorSpace = renderObject->style()->colorSpace();
838
839     paintInfo.context->drawTiledImage(barImage, colorSpace, rect, IntPoint(0, 0), barTileSize);
840
841     IntRect valueRect = progressValueRectFor(renderProgress, rect);
842     if (valueRect.width()) {
843
844         IntSize valueTileSize(std::max(1, static_cast<int>(valueImage->width() * tileScale)), valueRect.height());
845
846         int leftOffset = valueRect.x() - rect.x();
847         int roundedLeftOffset= (leftOffset / valueTileSize.width()) * valueTileSize.width();
848         int dstLeftValueWidth = roundedLeftOffset - leftOffset + (leftOffset % valueImage->width()) ? valueTileSize.width() : 0;
849
850         IntRect dstLeftValueRect(valueRect.x(), valueRect.y(), dstLeftValueWidth, valueRect.height());
851         int srcLeftValueWidth = dstLeftValueWidth / tileScale;
852         IntRect srcLeftValueRect(valueImage->width() - srcLeftValueWidth, 0, srcLeftValueWidth, valueImage->height());
853         paintInfo.context->drawImage(valueImage, colorSpace, dstLeftValueRect, srcLeftValueRect);
854
855         int rightOffset = valueRect.right() - rect.x();
856         int roundedRightOffset = (rightOffset / valueTileSize.width()) * valueTileSize.width();
857         int dstRightValueWidth = rightOffset - roundedRightOffset;
858         IntRect dstRightValueRect(rect.x() + roundedRightOffset, valueRect.y(), dstRightValueWidth, valueTileSize.height());
859         int srcRightValueWidth = dstRightValueWidth / tileScale;
860         IntRect srcRightValueRect(0, 0, srcRightValueWidth, valueImage->height());
861         paintInfo.context->drawImage(valueImage, colorSpace, dstRightValueRect, srcRightValueRect);
862         
863         IntRect alignedValueRect(dstLeftValueRect.right(), dstLeftValueRect.y(), 
864                                  dstRightValueRect.x() - dstLeftValueRect.right(), dstLeftValueRect.height());
865         paintInfo.context->drawTiledImage(valueImage, colorSpace, alignedValueRect, IntPoint(0, 0), valueTileSize);
866     }
867
868     int dstLeftBorderWidth = leftBorderImage->width() * tileScale;
869     IntRect dstLeftBorderRect(rect.x(), rect.y(), dstLeftBorderWidth, rect.height());
870     paintInfo.context->drawImage(leftBorderImage, colorSpace, dstLeftBorderRect, leftBorderImage->rect());
871
872     int dstRightBorderWidth = rightBorderImage->width() * tileScale;
873     IntRect dstRightBorderRect(rect.right() - dstRightBorderWidth, rect.y(), dstRightBorderWidth, rect.height());
874     paintInfo.context->drawImage(rightBorderImage, colorSpace, dstRightBorderRect, rightBorderImage->rect());
875
876     paintInfo.context->platformContext()->clearImageResamplingHint();
877
878     return false;
879 }
880
881
882 IntRect RenderThemeChromiumSkia::progressValueRectFor(RenderProgress* renderProgress, const IntRect& rect) const
883 {
884     return renderProgress->isDeterminate() ? determinateProgressValueRectFor(renderProgress, rect) : indeterminateProgressValueRectFor(renderProgress, rect);
885 }
886
887 #endif
888
889 } // namespace WebCore