[Qt] Broken controls rendering when transform is applied.
[WebKit-https.git] / Source / WebCore / platform / qt / RenderThemeQtMobile.cpp
1 /*
2  * This file is part of the WebKit project.
3  *
4  * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
5  *
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.
10  *
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.
15  *
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.
20  *
21  */
22
23 #include "config.h"
24 #include "RenderThemeQtMobile.h"
25
26 #include "CSSValueKeywords.h"
27 #include "Color.h"
28 #include "Document.h"
29 #include "Font.h"
30 #include "HTMLInputElement.h"
31 #include "HTMLNames.h"
32 #include "HTMLSelectElement.h"
33 #include "LocalizedStrings.h"
34 #include "NotImplemented.h"
35 #include "Page.h"
36 #include "PaintInfo.h"
37 #include "QWebPageClient.h"
38 #include "RenderBox.h"
39 #if ENABLE(PROGRESS_TAG)
40 #include "RenderProgress.h"
41 #endif
42 #include "StyleResolver.h"
43
44 #include <wtf/PassRefPtr.h>
45
46 #include <QColor>
47 #include <QFile>
48 #include <QPainter>
49 #include <QPixmapCache>
50
51 namespace WebCore {
52
53 using namespace HTMLNames;
54
55 // Constants used by the mobile theme
56 static const int arrowBoxWidth = 26;
57 static const int frameWidth = 2;
58 static const int checkBoxWidth = 21;
59 static const int radioWidth = 21;
60 static const int sliderSize = 20;
61 static const int buttonHeightRatio = 1.5;
62
63 static const float multipleComboDotsOffsetFactor = 1.8;
64 static const float buttonPaddingLeft = 18;
65 static const float buttonPaddingRight = 18;
66 static const float buttonPaddingTop = 2;
67 static const float buttonPaddingBottom = 3;
68 static const float menuListPadding = 9;
69 static const float textFieldPadding = 5;
70 static const float radiusFactor = 0.36;
71 static const float progressBarChunkPercentage = 0.2;
72 #if ENABLE(PROGRESS_TAG)
73 static const int progressAnimationGranularity = 2;
74 #endif
75 static const float sliderGrooveBorderRatio = 0.2;
76 static const QColor darkColor(40, 40, 40);
77 static const QColor highlightColor(16, 128, 221);
78 static const QColor buttonGradientBottom(245, 245, 245);
79 static const QColor shadowColor(80, 80, 80, 160);
80
81 static QHash<KeyIdentifier, CacheKey> cacheKeys;
82
83 static qreal painterScale(QPainter* painter)
84 {
85     if (!painter)
86         return 1;
87
88     const QTransform& transform = painter->transform();
89     qreal scale = 1;
90
91     if (transform.type() == QTransform::TxScale)
92         scale = qAbs(transform.m11());
93     else if (transform.type() >= QTransform::TxRotate) {
94         const QLineF l1(0, 0, 1, 0);
95         const QLineF l2 = transform.map(l1);
96         scale = qAbs(l2.length() / l1.length());
97     }
98     return scale;
99 }
100
101 uint qHash(const KeyIdentifier& id)
102 {
103     const quint32 value = id.trait1 + (id.trait2 << 1) + (uint(id.type) << 2) + (id.height << 5) + (id.width << 14) + (id.trait3 << 25);
104     const unsigned char* p = reinterpret_cast<const unsigned char*>(&value);
105     uint hash = 0;
106     for (int i = 0; i < 4; ++i)
107         hash ^= (hash << 5) + (hash >> 2) + p[i];
108     return hash;
109 }
110
111 static void drawControlBackground(QPainter* painter, const QPen& pen, const QRect& rect, const QBrush& brush)
112 {
113     QPen oldPen = painter->pen();
114     QBrush oldBrush = painter->brush();
115     painter->setRenderHint(QPainter::Antialiasing, true);
116     painter->setPen(pen);
117     painter->setBrush(brush);
118
119     const int line = 1;
120     const QRect paddedRect = rect.adjusted(line, line, -line, -line);
121
122     const int n = 3;
123     const qreal invPow = 1 / double(n);
124     ASSERT(paddedRect.width() >= paddedRect.height());
125     const int radius = paddedRect.height() / 2;
126     const int xDelta = paddedRect.width() / 2 - radius;
127     const QPoint center = paddedRect.topLeft() + QPoint(xDelta + radius, radius);
128     qreal x, y;
129     QPainterPath path;
130     path.moveTo(-xDelta, -radius);
131     for (y = -radius ; y <= radius; ++y) {
132         x = -xDelta - radius * pow(1 - pow(qAbs(y) / radius , n), invPow);
133         path.lineTo(x, y);
134     }
135     for (y = radius ; y >= -radius; --y) {
136         x =  xDelta + radius * pow(1 - pow(qAbs(y) / radius , n), invPow);
137         path.lineTo(x, y);
138     }
139     path.closeSubpath();
140     path.translate(center);
141
142     painter->drawPath(path);
143     painter->setPen(oldPen);
144     painter->setBrush(oldBrush);
145 }
146
147 static inline QRect shrinkRectToSquare(const QRect& rect)
148 {
149     const int side = qMin(rect.height(), rect.width());
150     return QRect(rect.topLeft(), QSize(side, side));
151 }
152
153 static inline QPen borderPen(QPainter* painter = 0)
154 {
155     return QPen(darkColor, 0.4 * painterScale(painter), Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
156 }
157
158 QSharedPointer<StylePainter> RenderThemeQtMobile::getStylePainter(const PaintInfo& pi)
159 {
160     return QSharedPointer<StylePainter>(new StylePainterMobile(this, pi));
161 }
162
163 StylePainterMobile::StylePainterMobile(RenderThemeQtMobile* theme, const PaintInfo& paintInfo)
164     : StylePainter(theme, paintInfo)
165 {
166     m_previousSmoothPixmapTransform = painter->testRenderHint(QPainter::SmoothPixmapTransform);
167     if (!m_previousSmoothPixmapTransform)
168         painter->setRenderHint(QPainter::SmoothPixmapTransform);
169 }
170
171 StylePainterMobile::~StylePainterMobile()
172 {
173     painter->setRenderHints(QPainter::SmoothPixmapTransform, m_previousSmoothPixmapTransform);
174 }
175
176 bool StylePainterMobile::findCachedControl(const KeyIdentifier& keyId, QPixmap* result)
177 {
178     static CacheKey emptyKey;
179     CacheKey key = cacheKeys.value(keyId, emptyKey);
180     if (key == emptyKey)
181         return false;
182     const bool ret = QPixmapCache::find(key, result);
183     if (!ret)
184         cacheKeys.remove(keyId);
185     return ret;
186 }
187
188 void StylePainterMobile::insertIntoCache(const KeyIdentifier& keyId, const QPixmap& pixmap)
189 {
190     ASSERT(keyId.type);
191     const int sizeInKiloBytes = pixmap.width() * pixmap.height() * pixmap.depth() / (8 * 1024);
192     // Don't cache pixmaps over 512 KB;
193     if (sizeInKiloBytes > 512)
194         return;
195     cacheKeys.insert(keyId, QPixmapCache::insert(pixmap));
196 }
197
198 void StylePainterMobile::drawCheckableBackground(QPainter* painter, const QRect& rect, bool checked, bool enabled) const
199 {
200     QBrush brush;
201     QColor color = Qt::gray;
202     if (checked && enabled)
203         color = highlightColor;
204
205     QLinearGradient gradient;
206     gradient.setStart(rect.topLeft());
207     gradient.setFinalStop(rect.bottomLeft());
208     gradient.setColorAt(0.0, color);
209     gradient.setColorAt(1.0, color.lighter(130));
210     brush = gradient;
211
212     drawControlBackground(painter, borderPen(painter), rect, brush);
213 }
214
215 QSize StylePainterMobile::sizeForPainterScale(const QRect& rect) const
216 {
217     qreal scale = painterScale(painter);
218     QTransform scaleTransform = QTransform::fromScale(scale, scale);
219
220     return scaleTransform.mapRect(rect).size();
221 }
222
223 void StylePainterMobile::drawChecker(QPainter* painter, const QRect& rect, const QColor& color) const
224 {
225     painter->setRenderHint(QPainter::Antialiasing, true);
226     QPen pen(Qt::darkGray);
227     pen.setCosmetic(true);
228     painter->setPen(pen);
229     painter->scale(rect.width(), rect.height());
230     QPainterPath path;
231     path.moveTo(0.18, 0.47);
232     path.lineTo(0.25, 0.4);
233     path.lineTo(0.4, 0.55);
234     path.quadTo(0.64, 0.29, 0.78, 0.2);
235     path.lineTo(0.8, 0.25);
236     path.quadTo(0.53, 0.55, 0.45, 0.75);
237     path.closeSubpath();
238     painter->setBrush(color);
239     painter->drawPath(path);
240 }
241
242 QPixmap StylePainterMobile::findCheckBox(const QSize& size, bool checked, bool enabled) const
243 {
244     ASSERT(size.width() == size.height());
245     QPixmap result;
246     KeyIdentifier id;
247     id.type = KeyIdentifier::CheckBox;
248     id.height = size.height();
249     id.trait1 = enabled;
250     id.trait2 = checked;
251     if (!findCachedControl(id, &result)) {
252         result = QPixmap(size);
253         result.fill(Qt::transparent);
254         QPainter cachePainter(&result);
255         QRect rect(QPoint(0, 0), size);
256         drawCheckableBackground(&cachePainter, rect, checked, enabled);
257         if (checked || !enabled)
258             drawChecker(&cachePainter, rect, enabled ? Qt::white : Qt::gray);
259         insertIntoCache(id, result);
260     }
261     return result;
262 }
263
264 void StylePainterMobile::drawRadio(QPainter* painter, const QSize& size, bool checked, bool enabled) const
265 {
266     QRect rect(QPoint(0, 0), size);
267
268     drawCheckableBackground(painter, rect, checked, enabled);
269     const int border = size.width() / 4;
270     rect.adjust(border, border, -border, -border);
271     drawControlBackground(painter, borderPen(), rect, enabled ? Qt::white : Qt::gray);
272 }
273
274 QPixmap StylePainterMobile::findRadio(const QSize& size, bool checked, bool enabled) const
275 {
276     ASSERT(size.width() == size.height());
277     QPixmap result;
278     KeyIdentifier id;
279     id.type = KeyIdentifier::Radio;
280     id.height = size.height();
281     id.trait1 = enabled;
282     id.trait2 = checked;
283     if (!findCachedControl(id, &result)) {
284         result = QPixmap(size);
285         result.fill(Qt::transparent);
286         QPainter cachePainter(&result);
287         drawRadio(&cachePainter, size, checked, enabled);
288         insertIntoCache(id, result);
289     }
290     return result;
291 }
292
293 void StylePainterMobile::drawMultipleComboButton(QPainter* painter, const QSizeF& size, const QColor& color) const
294 {
295     const qreal dotDiameter = size.height();
296     const qreal dotRadii = dotDiameter / 2;
297
298     painter->setRenderHint(QPainter::Antialiasing, true);
299     painter->setPen(color);
300     painter->setBrush(color);
301
302     for (int i = 0; i < 3; ++i) {
303         QPointF center(dotRadii + i * multipleComboDotsOffsetFactor * dotDiameter, dotRadii);
304         painter->drawEllipse(center, dotRadii, dotRadii);
305     }
306 }
307
308 void StylePainterMobile::drawSimpleComboButton(QPainter* painter, const QSizeF& size, const QColor& color) const
309 {
310     const qreal gap = size.height() / 5.0;
311     const qreal arrowHeight = (size.height() - gap) / 2.0;
312     const qreal right = arrowHeight * 2;
313     const qreal bottomBaseline = size.height() - arrowHeight;
314     QPolygonF upArrow, downArrow;
315     upArrow << QPointF(0, arrowHeight) << QPointF(arrowHeight, 0) << QPointF(right, arrowHeight);
316     downArrow << QPointF(0, bottomBaseline) << QPointF(arrowHeight, bottomBaseline + arrowHeight)
317               << QPointF(right, bottomBaseline);
318
319     painter->setPen(Qt::NoPen);
320     painter->setBrush(color);
321     painter->drawPolygon(upArrow);
322     painter->drawPolygon(downArrow);
323 }
324
325 QSizeF StylePainterMobile::getButtonImageSize(int buttonHeight, bool multiple) const
326 {
327     if (multiple)
328         return QSizeF(qreal(2 + buttonHeight * 3 * multipleComboDotsOffsetFactor/ 10.0)
329                       , qreal(2 + buttonHeight / 10.0));
330
331     const qreal height = buttonHeight / 2.5;
332     const qreal width = 4 * height / 5.0;
333     return QSizeF(2 + width, 2 + height);
334 }
335
336 QPixmap StylePainterMobile::findComboButton(const QSize& size, bool multiple, bool enabled) const
337 {
338     if (size.isNull())
339         return QPixmap();
340     QPixmap result;
341     KeyIdentifier id;
342     id.type = KeyIdentifier::ComboButton;
343     id.width = size.width();
344     id.height = size.height();
345     id.trait1 = multiple;
346     id.trait2 = enabled;
347
348     if (!findCachedControl(id, &result)) {
349         result = QPixmap(size);
350         const qreal border = painterScale(painter);
351         const QSizeF padding(2 * border, 2 * border);
352         const QSizeF innerSize = size - padding;
353         ASSERT(innerSize.isValid());
354         result.fill(Qt::transparent);
355         QPainter cachePainter(&result);
356         cachePainter.translate(border, border);
357         if (multiple)
358             drawMultipleComboButton(&cachePainter, innerSize, enabled ? darkColor : Qt::lightGray);
359         else
360             drawSimpleComboButton(&cachePainter, innerSize, enabled ? darkColor : Qt::lightGray);
361         insertIntoCache(id, result);
362     }
363     return result;
364 }
365
366 void StylePainterMobile::drawLineEdit(const QRect& rect, bool focused, bool enabled)
367 {
368     Q_UNUSED(enabled);
369     QPixmap lineEdit = findLineEdit(sizeForPainterScale(rect), focused);
370     if (lineEdit.isNull())
371         return;
372     painter->drawPixmap(rect, lineEdit);
373 }
374
375 QPixmap StylePainterMobile::findLineEdit(const QSize & size, bool focused) const
376 {
377     QPixmap result;
378     KeyIdentifier id;
379     id.type = KeyIdentifier::LineEdit;
380     id.width = size.width();
381     id.height = size.height();
382     id.trait1 = focused;
383
384     if (!findCachedControl(id, &result)) {
385         const int focusFrame = painterScale(painter);
386         result = QPixmap(size + QSize(2 * focusFrame, 2 * focusFrame));
387         result.fill(Qt::transparent);
388         const QRect rect = result.rect().adjusted(focusFrame, focusFrame, -focusFrame, -focusFrame);
389         QPainter cachePainter(&result);
390         drawControlBackground(&cachePainter, borderPen(painter), rect, Qt::white);
391
392         if (focused) {
393             QPen focusPen(highlightColor, focusFrame, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
394             drawControlBackground(&cachePainter, focusPen, rect, Qt::NoBrush);
395         }
396         insertIntoCache(id, result);
397     }
398     return result;
399 }
400
401 void StylePainterMobile::drawCheckBox(const QRect& rect, bool checked, bool enabled)
402 {
403     const QRect square = shrinkRectToSquare(rect);
404     QPixmap checkBox = findCheckBox(sizeForPainterScale(square), checked, enabled);
405     if (checkBox.isNull())
406         return;
407     painter->drawPixmap(square, checkBox);
408 }
409
410 void StylePainterMobile::drawRadioButton(const QRect& rect, bool checked, bool enabled)
411 {
412     const QRect square = shrinkRectToSquare(rect);
413     QPixmap radio = findRadio(sizeForPainterScale(square), checked, enabled);
414     if (radio.isNull())
415         return;
416     painter->drawPixmap(square, radio);
417 }
418
419 void StylePainterMobile::drawPushButton(const QRect& rect, bool sunken, bool enabled)
420 {
421     QPixmap pushButton = findPushButton(sizeForPainterScale(rect), sunken, enabled);
422     if (pushButton.isNull())
423         return;
424     painter->drawPixmap(rect, pushButton);
425 }
426
427 QPixmap StylePainterMobile::findPushButton(const QSize& size, bool sunken, bool enabled) const
428 {
429     QPixmap result;
430     KeyIdentifier id;
431     id.type = KeyIdentifier::PushButton;
432     id.width = size.width();
433     id.height = size.height();
434     id.trait1 = sunken;
435     id.trait2 = enabled;
436     if (!findCachedControl(id, &result)) {
437         const qreal dropShadowSize = painterScale(painter);
438         result = QPixmap(size);
439         result.fill(Qt::transparent);
440         const QRect rect = QRect(0, 0, size.width(), size.height() - dropShadowSize);
441         QPainter cachePainter(&result);
442         drawControlBackground(&cachePainter, Qt::NoPen, rect.adjusted(0, dropShadowSize, 0, dropShadowSize), shadowColor);
443
444         QBrush brush;
445         if (enabled && !sunken) {
446             QLinearGradient linearGradient;
447             linearGradient.setStart(rect.bottomLeft());
448             linearGradient.setFinalStop(rect.topLeft());
449             linearGradient.setColorAt(0.0, buttonGradientBottom);
450             linearGradient.setColorAt(1.0, Qt::white);
451             brush = linearGradient;
452         } else if (!enabled)
453             brush = QColor(241, 242, 243);
454         else { // sunken
455             QLinearGradient linearGradient;
456             linearGradient.setStart(rect.bottomLeft());
457             linearGradient.setFinalStop(rect.topLeft());
458             linearGradient.setColorAt(0.0, highlightColor);
459             linearGradient.setColorAt(1.0, highlightColor.lighter());
460             brush = linearGradient;
461         }
462         drawControlBackground(&cachePainter, borderPen(painter), rect, brush);
463         insertIntoCache(id, result);
464     }
465     return result;
466 }
467
468 void StylePainterMobile::drawComboBox(const QRect& rect, bool multiple, bool enabled)
469 {
470     QPixmap pushButton = findPushButton(sizeForPainterScale(rect), /*sunken = */false, enabled);
471     if (pushButton.isNull())
472         return;
473     painter->drawPixmap(rect, pushButton);
474     QRectF targetRect(QPointF(0, 0), getButtonImageSize(rect.height() - 1, multiple));
475     const QPointF buttonCenter(rect.right() - arrowBoxWidth / 2, rect.top() + (rect.height() - 1) / 2);
476     targetRect.moveCenter(buttonCenter);
477     QPixmap pic = findComboButton(sizeForPainterScale(targetRect.toRect()), multiple, enabled);
478     if (pic.isNull())
479         return;
480
481     painter->drawPixmap(targetRect.toRect(), pic);
482 }
483
484 void StylePainterMobile::drawProgress(const QRect& rect, double progress, bool leftToRight, bool animated, bool vertical) const
485 {
486     const int horizontalBorder = (vertical ? rect.width() / 4 : 0);
487     const int verticalBorder = (vertical ? 0 : rect.height() / 4);
488     const QRect targetRect = rect.adjusted(horizontalBorder, verticalBorder, -horizontalBorder, -verticalBorder);
489
490     QPixmap result;
491     QSize imageSize = sizeForPainterScale(targetRect);
492     if (vertical)
493         qSwap(imageSize.rheight(), imageSize.rwidth());
494     KeyIdentifier id;
495     id.type = KeyIdentifier::Progress;
496     id.width = imageSize.width();
497     id.height = imageSize.height();
498     id.trait1 = animated;
499     id.trait2 = (!animated && !leftToRight);
500     id.trait3 = progress * 100;
501     if (!findCachedControl(id, &result)) {
502         if (imageSize.isNull())
503             return;
504         result = QPixmap(imageSize);
505         result.fill(Qt::transparent);
506         QPainter painter(&result);
507         painter.setRenderHint(QPainter::Antialiasing);
508         QRect progressRect(QPoint(0, 0), imageSize);
509         qreal radius = radiusFactor * progressRect.height();
510         painter.setBrush(Qt::NoBrush);
511         painter.setPen(borderPen());
512         progressRect.adjust(1, 1, -1, -1);
513         painter.drawRoundedRect(progressRect, radius, radius);
514         progressRect.adjust(1, 1, -1, -1);
515         if (animated) {
516             const int right = progressRect.right();
517             const int startPos = right * (1 - progressBarChunkPercentage) * 2 * fabs(progress - 0.5);
518             progressRect.setWidth(progressBarChunkPercentage * right);
519             progressRect.moveLeft(startPos);
520         } else {
521             progressRect.setWidth(progress * progressRect.width());
522             if (!leftToRight)
523                 progressRect.moveRight(imageSize.width() - 2);
524         }
525         if (progressRect.width() > 0) {
526             QLinearGradient gradient;
527             gradient.setStart(progressRect.bottomLeft());
528             gradient.setFinalStop(progressRect.topLeft());
529             gradient.setColorAt(0.0, highlightColor);
530             gradient.setColorAt(1.0, highlightColor.lighter());
531             painter.setBrush(gradient);
532             painter.setPen(Qt::NoPen);
533             radius = radiusFactor * progressRect.height();
534             painter.drawRoundedRect(progressRect, radius, radius);
535         }
536         insertIntoCache(id, result);
537     }
538     QTransform transform;
539     transform.rotate(-90);
540     painter->drawPixmap(targetRect, vertical ? result.transformed(transform) : result);
541 }
542
543 void StylePainterMobile::drawSliderThumb(const QRect & rect, bool pressed) const
544 {
545     QPixmap result;
546     const QSize size = sizeForPainterScale(rect);
547     KeyIdentifier id;
548     id.type = KeyIdentifier::SliderThumb;
549     id.width = size.width();
550     id.height = size.height();
551     id.trait1 = pressed;
552     if (!findCachedControl(id, &result)) {
553         if (size.isNull())
554             return;
555         result = QPixmap(size);
556         result.fill(Qt::transparent);
557         QPainter cachePainter(&result);
558         drawControlBackground(&cachePainter, borderPen(painter), QRect(QPoint(0, 0), size), pressed? Qt::lightGray : buttonGradientBottom);
559         insertIntoCache(id, result);
560     }
561     painter->drawPixmap(rect, result);
562 }
563
564
565 PassRefPtr<RenderTheme> RenderThemeQtMobile::create(Page* page)
566 {
567     return adoptRef(new RenderThemeQtMobile(page));
568 }
569
570 RenderThemeQtMobile::RenderThemeQtMobile(Page* page)
571     : RenderThemeQt(page)
572 {
573 }
574
575 RenderThemeQtMobile::~RenderThemeQtMobile()
576 {
577 }
578
579 bool RenderThemeQtMobile::isControlStyled(const RenderStyle* style, const BorderData& border, const FillLayer& fill, const Color& backgroundColor) const
580 {
581     switch (style->appearance()) {
582     case CheckboxPart:
583     case RadioPart:
584         return false;
585     default:
586         return RenderThemeQt::isControlStyled(style, border, fill, backgroundColor);
587     }
588 }
589
590 int RenderThemeQtMobile::popupInternalPaddingBottom(RenderStyle* style) const
591 {
592     return 1;
593 }
594
595 void RenderThemeQtMobile::computeSizeBasedOnStyle(RenderStyle* renderStyle) const
596 {
597     QSize size(0, 0);
598
599     switch (renderStyle->appearance()) {
600     case TextAreaPart:
601     case SearchFieldPart:
602     case TextFieldPart: {
603         int padding = frameWidth;
604         renderStyle->setPaddingLeft(Length(padding, Fixed));
605         renderStyle->setPaddingRight(Length(padding, Fixed));
606         renderStyle->setPaddingTop(Length(padding, Fixed));
607         renderStyle->setPaddingBottom(Length(padding, Fixed));
608         break;
609     }
610     default:
611         break;
612     }
613     // If the width and height are both specified, then we have nothing to do.
614     if (!renderStyle->width().isIntrinsicOrAuto() && !renderStyle->height().isAuto())
615         return;
616
617     switch (renderStyle->appearance()) {
618     case CheckboxPart: {
619         const int w = checkBoxWidth * renderStyle->effectiveZoom();
620         size = QSize(w, w);
621         break;
622     }
623     case RadioPart: {
624         const int w = radioWidth * renderStyle->effectiveZoom();
625         size = QSize(w, w);
626         break;
627     }
628     case PushButtonPart:
629     case SquareButtonPart:
630     case DefaultButtonPart:
631     case ButtonPart:
632     case MenulistPart: {
633         const int height = renderStyle->fontMetrics().height() * buttonHeightRatio * renderStyle->effectiveZoom();
634         size = QSize(renderStyle->width().value(), height);
635         break;
636     }
637     default:
638         break;
639     }
640
641     // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
642     if (renderStyle->width().isIntrinsicOrAuto() && size.width() > 0)
643         renderStyle->setMinWidth(Length(size.width(), Fixed));
644     if (renderStyle->height().isAuto() && size.height() > 0)
645         renderStyle->setMinHeight(Length(size.height(), Fixed));
646 }
647
648 void RenderThemeQtMobile::adjustButtonStyle(StyleResolver*, RenderStyle* style, Element*) const
649 {
650     // Ditch the border.
651     style->resetBorder();
652
653     FontDescription fontDescription = style->fontDescription();
654     fontDescription.setIsAbsoluteSize(true);
655
656     fontDescription.setSpecifiedSize(style->fontSize());
657     fontDescription.setComputedSize(style->fontSize());
658
659     style->setLineHeight(RenderStyle::initialLineHeight());
660     setButtonSize(style);
661     setButtonPadding(style);
662 }
663
664 void RenderThemeQtMobile::setButtonPadding(RenderStyle* style) const
665 {
666     if (!style)
667         return;
668     style->setPaddingLeft(Length(buttonPaddingLeft, Fixed));
669     style->setPaddingRight(Length(buttonPaddingRight, Fixed));
670     style->setPaddingTop(Length(buttonPaddingTop, Fixed));
671     style->setPaddingBottom(Length(buttonPaddingBottom, Fixed));
672 }
673
674 bool RenderThemeQtMobile::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& r)
675 {
676     StylePainterMobile p(this, i);
677     if (!p.isValid())
678        return true;
679
680     ControlPart appearance = o->style()->appearance();
681     if (appearance == PushButtonPart || appearance == ButtonPart) {
682         p.drawPushButton(r, isPressed(o), isEnabled(o));
683     } else if (appearance == RadioPart)
684        p.drawRadioButton(r, isChecked(o), isEnabled(o));
685     else if (appearance == CheckboxPart)
686        p.drawCheckBox(r, isChecked(o), isEnabled(o));
687
688     return false;
689 }
690
691 void RenderThemeQtMobile::adjustTextFieldStyle(StyleResolver*, RenderStyle* style, Element*) const
692 {
693     // Resetting the style like this leads to differences like:
694     // - RenderTextControl {INPUT} at (2,2) size 168x25 [bgcolor=#FFFFFF] border: (2px inset #000000)]
695     // + RenderTextControl {INPUT} at (2,2) size 166x26
696     // in layout tests when a CSS style is applied that doesn't affect background color, border or
697     // padding. Just worth keeping in mind!
698     style->setBackgroundColor(Color::transparent);
699     style->resetBorder();
700     style->resetPadding();
701     computeSizeBasedOnStyle(style);
702     style->setPaddingLeft(Length(textFieldPadding, Fixed));
703     style->setPaddingRight(Length(textFieldPadding, Fixed));
704 }
705
706 bool RenderThemeQtMobile::paintTextField(RenderObject* o, const PaintInfo& i, const IntRect& r)
707 {
708     StylePainterMobile p(this, i);
709     if (!p.isValid())
710         return true;
711
712     ControlPart appearance = o->style()->appearance();
713     if (appearance != TextFieldPart
714         && appearance != SearchFieldPart
715         && appearance != TextAreaPart)
716         return true;
717
718     // Now paint the text field.
719     if (appearance == TextAreaPart) {
720         const bool previousAntialiasing = p.painter->testRenderHint(QPainter::Antialiasing);
721         p.painter->setRenderHint(QPainter::Antialiasing);
722         p.painter->setPen(borderPen());
723         p.painter->setBrush(Qt::white);
724         const int radius = checkBoxWidth * radiusFactor;
725         p.painter->drawRoundedRect(r, radius, radius);
726
727         if (isFocused(o)) {
728             QPen focusPen(highlightColor, 1.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
729             p.painter->setPen(focusPen);
730             p.painter->setBrush(Qt::NoBrush);
731             p.painter->drawRoundedRect(r, radius, radius);
732         }
733         p.painter->setRenderHint(QPainter::Antialiasing, previousAntialiasing);
734     } else
735         p.drawLineEdit(r, isFocused(o), isEnabled(o));
736     return false;
737 }
738
739 void RenderThemeQtMobile::adjustMenuListStyle(StyleResolver* styleResolver, RenderStyle* style, Element* e) const
740 {
741     RenderThemeQt::adjustMenuListStyle(styleResolver, style, e);
742     style->setPaddingLeft(Length(menuListPadding, Fixed));
743 }
744
745 void RenderThemeQtMobile::setPopupPadding(RenderStyle* style) const
746 {
747     const int paddingLeft = 4;
748     const int paddingRight = style->width().isFixed() || style->width().isPercent() ? 5 : 8;
749
750     style->setPaddingLeft(Length(paddingLeft, Fixed));
751     style->setPaddingRight(Length(paddingRight + arrowBoxWidth, Fixed));
752
753     style->setPaddingTop(Length(2, Fixed));
754     style->setPaddingBottom(Length(2, Fixed));
755 }
756
757 bool RenderThemeQtMobile::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& r)
758 {
759     StylePainterMobile p(this, i);
760     if (!p.isValid())
761         return true;
762
763     p.drawComboBox(r, checkMultiple(o), isEnabled(o));
764     return false;
765 }
766
767 bool RenderThemeQtMobile::paintMenuListButton(RenderObject* o, const PaintInfo& i,
768                                         const IntRect& r)
769 {
770     StylePainterMobile p(this, i);
771     if (!p.isValid())
772         return true;
773
774     p.drawComboBox(r, checkMultiple(o), isEnabled(o));
775
776     return false;
777 }
778
779 #if ENABLE(PROGRESS_TAG)
780 double RenderThemeQtMobile::animationDurationForProgressBar(RenderProgress* renderProgress) const
781 {
782     if (renderProgress->isDeterminate())
783         return 0;
784     // Our animation goes back and forth so we need to make it last twice as long
785     // and we need the numerator to be an odd number to ensure we get a progress value of 0.5.
786     return (2 * progressAnimationGranularity +1) / progressBarChunkPercentage * animationRepeatIntervalForProgressBar(renderProgress);
787 }
788
789 bool RenderThemeQtMobile::paintProgressBar(RenderObject* o, const PaintInfo& pi, const IntRect& r)
790 {
791     if (!o->isProgress())
792         return true;
793
794     StylePainterMobile p(this, pi);
795     if (!p.isValid())
796         return true;
797
798     RenderProgress* renderProgress = toRenderProgress(o);
799     const bool isRTL = (renderProgress->style()->direction() == RTL);
800
801     if (renderProgress->isDeterminate())
802         p.drawProgress(r, renderProgress->position(), !isRTL);
803     else
804         p.drawProgress(r, renderProgress->animationProgress(), !isRTL, true);
805
806     return false;
807 }
808 #endif
809
810 bool RenderThemeQtMobile::paintSliderTrack(RenderObject* o, const PaintInfo& pi,
811                                      const IntRect& r)
812 {
813     StylePainterMobile p(this, pi);
814     if (!p.isValid())
815         return true;
816
817     HTMLInputElement* slider = static_cast<HTMLInputElement*>(o->node());
818
819     const double min = slider->minimum();
820     const double max = slider->maximum();
821     const double progress = (max - min > 0) ? (slider->valueAsNumber() - min) / (max - min) : 0;
822
823     QRect rect(r);
824     const bool vertical = (o->style()->appearance() == SliderVerticalPart);
825     const int groovePadding = vertical ? r.width() * sliderGrooveBorderRatio : r.height() * sliderGrooveBorderRatio;
826     if (vertical)
827         rect.adjust(groovePadding, 0, -groovePadding, 0);
828     else
829         rect.adjust(0, groovePadding, 0, -groovePadding);
830     p.drawProgress(rect, progress, o->style()->isLeftToRightDirection(), /*animated = */ false, vertical);
831
832     return false;
833 }
834
835 bool RenderThemeQtMobile::paintSliderThumb(RenderObject* o, const PaintInfo& pi,
836                                      const IntRect& r)
837 {
838     StylePainterMobile p(this, pi);
839     if (!p.isValid())
840         return true;
841
842     p.drawSliderThumb(r, isPressed(o));
843
844     return false;
845 }
846
847 bool RenderThemeQtMobile::checkMultiple(RenderObject* o) const
848 {
849     HTMLSelectElement* select = o ? static_cast<HTMLSelectElement*>(o->node()) : 0;
850     return select ? select->multiple() : false;
851 }
852
853 void RenderThemeQtMobile::setPaletteFromPageClientIfExists(QPalette& palette) const
854 {
855     static QPalette lightGrayPalette(Qt::lightGray);
856     palette = lightGrayPalette;
857     return;
858 }
859
860 void RenderThemeQtMobile::adjustSliderThumbSize(RenderStyle* style) const
861 {
862     const ControlPart part = style->appearance();
863     if (part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart) {
864         const int size = sliderSize * style->effectiveZoom();
865         style->setWidth(Length(size, Fixed));
866         style->setHeight(Length(size, Fixed));
867     } else
868         RenderThemeQt::adjustSliderThumbSize(style);
869 }
870
871 }
872
873 // vim: ts=4 sw=4 et