2 * This file is part of the theme implementation for form controls in WebCore.
4 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Computer, Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
23 #include "core/paint/ThemePainter.h"
25 #include "core/InputTypeNames.h"
26 #include "core/html/HTMLDataListElement.h"
27 #include "core/html/HTMLDataListOptionsCollection.h"
28 #include "core/html/HTMLInputElement.h"
29 #include "core/html/HTMLOptionElement.h"
30 #include "core/html/parser/HTMLParserIdioms.h"
31 #include "core/html/shadow/ShadowElementNames.h"
32 #include "core/layout/LayoutMeter.h"
33 #include "core/layout/LayoutTheme.h"
34 #include "core/layout/LayoutView.h"
35 #include "core/paint/MediaControlsPainter.h"
36 #include "core/paint/PaintInfo.h"
37 #include "core/style/ComputedStyle.h"
38 #include "platform/graphics/GraphicsContextStateSaver.h"
39 #include "public/platform/Platform.h"
40 #include "public/platform/WebFallbackThemeEngine.h"
41 #include "public/platform/WebRect.h"
44 #include "platform/Theme.h"
47 // The methods in this file are shared by all themes on every platform.
51 static WebFallbackThemeEngine::State
getWebFallbackThemeState(const LayoutObject
* o
)
53 if (!LayoutTheme::isEnabled(o
))
54 return WebFallbackThemeEngine::StateDisabled
;
55 if (LayoutTheme::isPressed(o
))
56 return WebFallbackThemeEngine::StatePressed
;
57 if (LayoutTheme::isHovered(o
))
58 return WebFallbackThemeEngine::StateHover
;
60 return WebFallbackThemeEngine::StateNormal
;
63 bool ThemePainter::paint(LayoutObject
* o
, const PaintInfo
& paintInfo
, const IntRect
& r
)
65 ControlPart part
= o
->styleRef().appearance();
67 if (LayoutTheme::theme().shouldUseFallbackTheme(o
->styleRef()))
68 return paintUsingFallbackTheme(o
, paintInfo
, r
);
75 case SquareButtonPart
:
77 case InnerSpinButtonPart
:
78 platformTheme()->paint(part
, LayoutTheme::controlStatesForLayoutObject(o
), const_cast<GraphicsContext
*>(paintInfo
.context
), r
, o
->styleRef().effectiveZoom(), o
->view()->frameView());
85 // Call the appropriate paint method based off the appearance value.
89 return paintCheckbox(o
, paintInfo
, r
);
91 return paintRadio(o
, paintInfo
, r
);
93 case SquareButtonPart
:
95 return paintButton(o
, paintInfo
, r
);
96 case InnerSpinButtonPart
:
97 return paintInnerSpinButton(o
, paintInfo
, r
);
100 return paintMenuList(o
, paintInfo
, r
);
102 case RelevancyLevelIndicatorPart
:
103 case ContinuousCapacityLevelIndicatorPart
:
104 case DiscreteCapacityLevelIndicatorPart
:
105 case RatingLevelIndicatorPart
:
106 return paintMeter(o
, paintInfo
, r
);
107 case ProgressBarPart
:
108 return paintProgressBar(o
, paintInfo
, r
);
109 case SliderHorizontalPart
:
110 case SliderVerticalPart
:
111 return paintSliderTrack(o
, paintInfo
, r
);
112 case SliderThumbHorizontalPart
:
113 case SliderThumbVerticalPart
:
114 return paintSliderThumb(o
, paintInfo
, r
);
115 case MediaEnterFullscreenButtonPart
:
116 case MediaExitFullscreenButtonPart
:
117 return MediaControlsPainter::paintMediaFullscreenButton(o
, paintInfo
, r
);
118 case MediaPlayButtonPart
:
119 return MediaControlsPainter::paintMediaPlayButton(o
, paintInfo
, r
);
120 case MediaOverlayPlayButtonPart
:
121 return MediaControlsPainter::paintMediaOverlayPlayButton(o
, paintInfo
, r
);
122 case MediaMuteButtonPart
:
123 return MediaControlsPainter::paintMediaMuteButton(o
, paintInfo
, r
);
124 case MediaToggleClosedCaptionsButtonPart
:
125 return MediaControlsPainter::paintMediaToggleClosedCaptionsButton(o
, paintInfo
, r
);
126 case MediaSliderPart
:
127 return MediaControlsPainter::paintMediaSlider(o
, paintInfo
, r
);
128 case MediaSliderThumbPart
:
129 return MediaControlsPainter::paintMediaSliderThumb(o
, paintInfo
, r
);
130 case MediaVolumeSliderContainerPart
:
132 case MediaVolumeSliderPart
:
133 return MediaControlsPainter::paintMediaVolumeSlider(o
, paintInfo
, r
);
134 case MediaVolumeSliderThumbPart
:
135 return MediaControlsPainter::paintMediaVolumeSliderThumb(o
, paintInfo
, r
);
136 case MediaFullScreenVolumeSliderPart
:
137 case MediaFullScreenVolumeSliderThumbPart
:
138 case MediaTimeRemainingPart
:
139 case MediaCurrentTimePart
:
140 case MediaControlsBackgroundPart
:
142 case MediaCastOffButtonPart
:
143 case MediaOverlayCastOffButtonPart
:
144 return MediaControlsPainter::paintMediaCastButton(o
, paintInfo
, r
);
145 case MenulistButtonPart
:
149 case SearchFieldPart
:
150 return paintSearchField(o
, paintInfo
, r
);
151 case SearchFieldCancelButtonPart
:
152 return paintSearchFieldCancelButton(o
, paintInfo
, r
);
153 case SearchFieldDecorationPart
:
154 return paintSearchFieldDecoration(o
, paintInfo
, r
);
155 case SearchFieldResultsDecorationPart
:
156 return paintSearchFieldResultsDecoration(o
, paintInfo
, r
);
161 return true; // We don't support the appearance, so let the normal background/border paint.
164 bool ThemePainter::paintBorderOnly(LayoutObject
* o
, const PaintInfo
& paintInfo
, const IntRect
& r
)
166 // Call the appropriate paint method based off the appearance value.
167 switch (o
->style()->appearance()) {
169 return paintTextField(o
, paintInfo
, r
);
171 return paintTextArea(o
, paintInfo
, r
);
172 case MenulistButtonPart
:
173 case SearchFieldPart
:
179 case SquareButtonPart
:
183 case RelevancyLevelIndicatorPart
:
184 case ContinuousCapacityLevelIndicatorPart
:
185 case DiscreteCapacityLevelIndicatorPart
:
186 case RatingLevelIndicatorPart
:
187 case ProgressBarPart
:
188 case SliderHorizontalPart
:
189 case SliderVerticalPart
:
190 case SliderThumbHorizontalPart
:
191 case SliderThumbVerticalPart
:
192 case SearchFieldCancelButtonPart
:
193 case SearchFieldDecorationPart
:
194 case SearchFieldResultsDecorationPart
:
202 bool ThemePainter::paintDecorations(LayoutObject
* o
, const PaintInfo
& paintInfo
, const IntRect
& r
)
204 // Call the appropriate paint method based off the appearance value.
205 switch (o
->style()->appearance()) {
206 case MenulistButtonPart
:
207 return paintMenuListButton(o
, paintInfo
, r
);
213 case SquareButtonPart
:
217 case RelevancyLevelIndicatorPart
:
218 case ContinuousCapacityLevelIndicatorPart
:
219 case DiscreteCapacityLevelIndicatorPart
:
220 case RatingLevelIndicatorPart
:
221 case ProgressBarPart
:
222 case SliderHorizontalPart
:
223 case SliderVerticalPart
:
224 case SliderThumbHorizontalPart
:
225 case SliderThumbVerticalPart
:
226 case SearchFieldPart
:
227 case SearchFieldCancelButtonPart
:
228 case SearchFieldDecorationPart
:
229 case SearchFieldResultsDecorationPart
:
237 bool ThemePainter::paintMeter(LayoutObject
*, const PaintInfo
&, const IntRect
&)
242 void ThemePainter::paintSliderTicks(LayoutObject
* o
, const PaintInfo
& paintInfo
, const IntRect
& rect
)
244 Node
* node
= o
->node();
245 if (!isHTMLInputElement(node
))
248 HTMLInputElement
* input
= toHTMLInputElement(node
);
249 if (input
->type() != InputTypeNames::range
)
252 HTMLDataListElement
* dataList
= input
->dataList();
256 double min
= input
->minimum();
257 double max
= input
->maximum();
258 ControlPart part
= o
->style()->appearance();
259 // We don't support ticks on alternate sliders like MediaVolumeSliders.
260 if (part
!= SliderHorizontalPart
&& part
!= SliderVerticalPart
)
262 bool isHorizontal
= part
== SliderHorizontalPart
;
265 LayoutObject
* thumbLayoutObject
= input
->userAgentShadowRoot()->getElementById(ShadowElementNames::sliderThumb())->layoutObject();
266 if (thumbLayoutObject
) {
267 const ComputedStyle
& thumbStyle
= thumbLayoutObject
->styleRef();
268 int thumbWidth
= thumbStyle
.width().intValue();
269 int thumbHeight
= thumbStyle
.height().intValue();
270 thumbSize
.setWidth(isHorizontal
? thumbWidth
: thumbHeight
);
271 thumbSize
.setHeight(isHorizontal
? thumbHeight
: thumbWidth
);
274 IntSize tickSize
= LayoutTheme::theme().sliderTickSize();
275 float zoomFactor
= o
->style()->effectiveZoom();
277 int tickRegionSideMargin
= 0;
278 int tickRegionWidth
= 0;
280 LayoutObject
* trackLayoutObject
= input
->userAgentShadowRoot()->getElementById(ShadowElementNames::sliderTrack())->layoutObject();
281 // We can ignoring transforms because transform is handled by the graphics context.
282 if (trackLayoutObject
)
283 trackBounds
= trackLayoutObject
->absoluteBoundingBoxRectIgnoringTransforms();
284 IntRect sliderBounds
= o
->absoluteBoundingBoxRectIgnoringTransforms();
286 // Make position relative to the transformed ancestor element.
287 trackBounds
.setX(trackBounds
.x() - sliderBounds
.x() + rect
.x());
288 trackBounds
.setY(trackBounds
.y() - sliderBounds
.y() + rect
.y());
291 tickRect
.setWidth(floor(tickSize
.width() * zoomFactor
));
292 tickRect
.setHeight(floor(tickSize
.height() * zoomFactor
));
293 tickRect
.setY(floor(rect
.y() + rect
.height() / 2.0 + LayoutTheme::theme().sliderTickOffsetFromTrackCenter() * zoomFactor
));
294 tickRegionSideMargin
= trackBounds
.x() + (thumbSize
.width() - tickSize
.width() * zoomFactor
) / 2.0;
295 tickRegionWidth
= trackBounds
.width() - thumbSize
.width();
297 tickRect
.setWidth(floor(tickSize
.height() * zoomFactor
));
298 tickRect
.setHeight(floor(tickSize
.width() * zoomFactor
));
299 tickRect
.setX(floor(rect
.x() + rect
.width() / 2.0 + LayoutTheme::theme().sliderTickOffsetFromTrackCenter() * zoomFactor
));
300 tickRegionSideMargin
= trackBounds
.y() + (thumbSize
.width() - tickSize
.width() * zoomFactor
) / 2.0;
301 tickRegionWidth
= trackBounds
.height() - thumbSize
.width();
303 RefPtrWillBeRawPtr
<HTMLDataListOptionsCollection
> options
= dataList
->options();
304 for (unsigned i
= 0; HTMLOptionElement
* optionElement
= options
->item(i
); i
++) {
305 String value
= optionElement
->value();
306 if (!input
->isValidValue(value
))
308 double parsedValue
= parseToDoubleForNumberType(input
->sanitizeValue(value
));
309 double tickFraction
= (parsedValue
- min
) / (max
- min
);
310 double tickRatio
= isHorizontal
&& o
->style()->isLeftToRightDirection() ? tickFraction
: 1.0 - tickFraction
;
311 double tickPosition
= round(tickRegionSideMargin
+ tickRegionWidth
* tickRatio
);
313 tickRect
.setX(tickPosition
);
315 tickRect
.setY(tickPosition
);
316 paintInfo
.context
->fillRect(tickRect
, o
->resolveColor(CSSPropertyColor
));
320 bool ThemePainter::paintUsingFallbackTheme(LayoutObject
* o
, const PaintInfo
& i
, const IntRect
& r
)
322 ControlPart part
= o
->style()->appearance();
325 return paintCheckboxUsingFallbackTheme(o
, i
, r
);
327 return paintRadioUsingFallbackTheme(o
, i
, r
);
334 bool ThemePainter::paintCheckboxUsingFallbackTheme(LayoutObject
* o
, const PaintInfo
& i
, const IntRect
& r
)
336 WebFallbackThemeEngine::ExtraParams extraParams
;
337 WebCanvas
* canvas
= i
.context
->canvas();
338 extraParams
.button
.checked
= LayoutTheme::isChecked(o
);
339 extraParams
.button
.indeterminate
= LayoutTheme::isIndeterminate(o
);
341 float zoomLevel
= o
->style()->effectiveZoom();
342 GraphicsContextStateSaver
stateSaver(*i
.context
);
343 IntRect unzoomedRect
= r
;
344 if (zoomLevel
!= 1) {
345 unzoomedRect
.setWidth(unzoomedRect
.width() / zoomLevel
);
346 unzoomedRect
.setHeight(unzoomedRect
.height() / zoomLevel
);
347 i
.context
->translate(unzoomedRect
.x(), unzoomedRect
.y());
348 i
.context
->scale(zoomLevel
, zoomLevel
);
349 i
.context
->translate(-unzoomedRect
.x(), -unzoomedRect
.y());
352 Platform::current()->fallbackThemeEngine()->paint(canvas
, WebFallbackThemeEngine::PartCheckbox
, getWebFallbackThemeState(o
), WebRect(unzoomedRect
), &extraParams
);
356 bool ThemePainter::paintRadioUsingFallbackTheme(LayoutObject
* o
, const PaintInfo
& i
, const IntRect
& r
)
358 WebFallbackThemeEngine::ExtraParams extraParams
;
359 WebCanvas
* canvas
= i
.context
->canvas();
360 extraParams
.button
.checked
= LayoutTheme::isChecked(o
);
361 extraParams
.button
.indeterminate
= LayoutTheme::isIndeterminate(o
);
363 float zoomLevel
= o
->style()->effectiveZoom();
364 GraphicsContextStateSaver
stateSaver(*i
.context
);
365 IntRect unzoomedRect
= r
;
366 if (zoomLevel
!= 1) {
367 unzoomedRect
.setWidth(unzoomedRect
.width() / zoomLevel
);
368 unzoomedRect
.setHeight(unzoomedRect
.height() / zoomLevel
);
369 i
.context
->translate(unzoomedRect
.x(), unzoomedRect
.y());
370 i
.context
->scale(zoomLevel
, zoomLevel
);
371 i
.context
->translate(-unzoomedRect
.x(), -unzoomedRect
.y());
374 Platform::current()->fallbackThemeEngine()->paint(canvas
, WebFallbackThemeEngine::PartRadio
, getWebFallbackThemeState(o
), WebRect(unzoomedRect
), &extraParams
);