RenderThemeChromiumWin.cpp 28.7 KB
Newer Older
1
2
3
4
5
/*
 * This file is part of the WebKit project.
 *
 * Copyright (C) 2006 Apple Computer, Inc.
 * Copyright (C) 2008, 2009 Google, Inc.
6
 * Copyright (C) 2009 Kenneth Rohde Christiansen
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 */

#include "config.h"
#include "RenderThemeChromiumWin.h"

#include <windows.h>
#include <uxtheme.h>
#include <vssym32.h>

#include "CSSValueKeywords.h"
33
#include "CurrentTime.h"
34
35
36
#include "FontSelector.h"
#include "FontUtilsChromiumWin.h"
#include "GraphicsContext.h"
37
38
39
#include "HTMLMediaElement.h"
#include "HTMLNames.h"
#include "MediaControlElements.h"
40
#include "PaintInfo.h"
41
#include "PlatformBridge.h"
42
#include "RenderBox.h"
43
#include "RenderProgress.h"
44
#include "RenderSlider.h"
45
#include "ScrollbarTheme.h"
46
#include "TransparencyWin.h"
47
48
49
50
51
52
53
54
55
56
57
58
59
#include "WindowsVersion.h"

// FIXME: This dependency should eventually be removed.
#include <skia/ext/skia_utils_win.h>

#define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(structName, member) \
    offsetof(structName, member) + \
    (sizeof static_cast<structName*>(0)->member)
#define NONCLIENTMETRICS_SIZE_PRE_VISTA \
    SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(NONCLIENTMETRICS, lfMessageFont)

namespace WebCore {

60
61
62
63
// The standard width for the menu list drop-down button when run under
// layout test mode. Use the value that's currently captured in most baselines.
static const int kStandardMenuListButtonWidth = 17;

64
namespace {
65
// We must not create multiple ThemePainter instances.
66
class ThemePainter {
67
68
69
public:
    ThemePainter(GraphicsContext* context, const IntRect& r)
    {
70
71
72
73
#ifndef NDEBUG
        ASSERT(!s_hasInstance);
        s_hasInstance = true;
#endif
74
75
76
77
78
79
80
81
82
83
84
85
86
87
        TransparencyWin::TransformMode transformMode = getTransformMode(context->getCTM());
        m_helper.init(context, getLayerMode(context, transformMode), transformMode, r);

        if (!m_helper.context()) {
            // TransparencyWin doesn't have well-defined copy-ctor nor op=()
            // so we re-initialize it instead of assigning a fresh istance.
            // On the reinitialization, we fallback to use NoLayer mode.
            // Note that the original initialization failure can be caused by
            // a failure of an internal buffer allocation and NoLayer mode
            // does not have such buffer allocations.
            m_helper.~TransparencyWin();
            new (&m_helper) TransparencyWin();
            m_helper.init(context, TransparencyWin::NoLayer, transformMode, r);
        }
88
89
    }

90
91
    ~ThemePainter()
    {
92
        m_helper.composite();
93
94
95
#ifndef NDEBUG
        s_hasInstance = false;
#endif
96
97
    }

98
99
100
    GraphicsContext* context() { return m_helper.context(); }
    const IntRect& drawRect() { return m_helper.drawRect(); }

101
private:
102

103
104
105
    static bool canvasHasMultipleLayers(const SkCanvas* canvas)
    {
        SkCanvas::LayerIter iter(const_cast<SkCanvas*>(canvas), false);
106
107
        iter.next(); // There is always at least one layer.
        return !iter.done(); // There is > 1 layer if the the iterator can stil advance.
108
109
    }

110
    static TransparencyWin::LayerMode getLayerMode(GraphicsContext* context, TransparencyWin::TransformMode transformMode)
111
    {
112
        if (context->platformContext()->isDrawingToImageBuffer()) // Might have transparent background.
113
            return TransparencyWin::WhiteLayer;
114
        if (canvasHasMultipleLayers(context->platformContext()->canvas())) // Needs antialiasing help.
115
            return TransparencyWin::OpaqueCompositeLayer;
116
117
        // Nothing interesting.
        return transformMode == TransparencyWin::KeepTransform ? TransparencyWin::NoLayer : TransparencyWin::OpaqueCompositeLayer;
118
119
    }

120
    static TransparencyWin::TransformMode getTransformMode(const AffineTransform& matrix)
121
    {
122
        if (matrix.b() || matrix.c()) // Skew.
123
            return TransparencyWin::Untransform;
124
        if (matrix.a() != 1.0 || matrix.d() != 1.0) // Scale.
125
            return TransparencyWin::ScaleTransform;
126
127
        // Nothing interesting.
        return TransparencyWin::KeepTransform;
128
    }
129
130

    TransparencyWin m_helper;
131
132
133
#ifndef NDEBUG
    static bool s_hasInstance;
#endif
134
135
};

136
137
138
139
#ifndef NDEBUG
bool ThemePainter::s_hasInstance = false;
#endif

140
} // namespace
141

142
143
static void getNonClientMetrics(NONCLIENTMETRICS* metrics)
{
144
    static UINT size = isVistaOrNewer() ?
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
        sizeof(NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA;
    metrics->cbSize = size;
    bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, size, metrics, 0);
    ASSERT(success);
}

static FontDescription smallSystemFont;
static FontDescription menuFont;
static FontDescription labelFont;

// Internal static helper functions.  We don't put them in an anonymous
// namespace so they have easier access to the WebCore namespace.

static bool supportsFocus(ControlPart appearance)
{
    switch (appearance) {
    case PushButtonPart:
    case ButtonPart:
    case DefaultButtonPart:
164
    case SearchFieldPart:
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
    case TextFieldPart:
    case TextAreaPart:
        return true;
    }
    return false;
}

// Return the height of system font |font| in pixels.  We use this size by
// default for some non-form-control elements.
static float systemFontSize(const LOGFONT& font)
{
    float size = -font.lfHeight;
    if (size < 0) {
        HFONT hFont = CreateFontIndirect(&font);
        if (hFont) {
180
            HDC hdc = GetDC(0); // What about printing?  Is this the right DC?
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
            if (hdc) {
                HGDIOBJ hObject = SelectObject(hdc, hFont);
                TEXTMETRIC tm;
                GetTextMetrics(hdc, &tm);
                SelectObject(hdc, hObject);
                ReleaseDC(0, hdc);
                size = tm.tmAscent;
            }
            DeleteObject(hFont);
        }
    }

    // The "codepage 936" bit here is from Gecko; apparently this helps make
    // fonts more legible in Simplified Chinese where the default font size is
    // too small.
    //
    // FIXME: http://b/1119883 Since this is only used for "small caption",
    // "menu", and "status bar" objects, I'm not sure how much this even
    // matters.  Plus the Gecko patch went in back in 2002, and maybe this
    // isn't even relevant anymore.  We should investigate whether this should
    // be removed, or perhaps broadened to be "any CJK locale".
    //
    return ((size < 12.0f) && (GetACP() == 936)) ? 12.0f : size;
}

// Converts |points| to pixels.  One point is 1/72 of an inch.
static float pointsToPixels(float points)
{
    static float pixelsPerInch = 0.0f;
    if (!pixelsPerInch) {
211
212
        HDC hdc = GetDC(0); // What about printing?  Is this the right DC?
        if (hdc) { // Can this ever actually be NULL?
213
214
215
216
217
218
219
220
221
222
223
224
225
226
            pixelsPerInch = GetDeviceCaps(hdc, LOGPIXELSY);
            ReleaseDC(0, hdc);
        } else {
            pixelsPerInch = 96.0f;
        }
    }

    static const float pointsPerInch = 72.0f;
    return points / pointsPerInch * pixelsPerInch;
}

static double querySystemBlinkInterval(double defaultInterval)
{
    UINT blinkTime = GetCaretBlinkTime();
227
    if (!blinkTime)
228
229
230
231
232
233
        return defaultInterval;
    if (blinkTime == INFINITE)
        return 0;
    return blinkTime / 1000.0;
}

234
PassRefPtr<RenderTheme> RenderThemeChromiumWin::create()
235
{
236
237
238
239
240
241
242
    return adoptRef(new RenderThemeChromiumWin);
}

PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
{
    static RenderTheme* rt = RenderThemeChromiumWin::create().releaseRef();
    return rt;
243
244
245
246
}

bool RenderThemeChromiumWin::supportsFocusRing(const RenderStyle* style) const
{
247
248
249
250
251
    // Let webkit draw one of its halo rings around any focused element,
    // except push buttons. For buttons we use the windows PBS_DEFAULTED
    // styling to give it a blue border.
    return style->appearance() == ButtonPart
            || style->appearance() == PushButtonPart;
252
253
254
255
}

Color RenderThemeChromiumWin::platformActiveSelectionBackgroundColor() const
{
256
    if (PlatformBridge::layoutTestMode())
257
        return Color(0x00, 0x00, 0xff); // Royal blue.
258
    COLORREF color = GetSysColor(COLOR_HIGHLIGHT);
259
    return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff);
260
261
262
263
}

Color RenderThemeChromiumWin::platformInactiveSelectionBackgroundColor() const
{
264
    if (PlatformBridge::layoutTestMode())
265
        return Color(0x99, 0x99, 0x99); // Medium gray.
266
    COLORREF color = GetSysColor(COLOR_GRAYTEXT);
267
    return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff);
268
269
270
271
}

Color RenderThemeChromiumWin::platformActiveSelectionForegroundColor() const
{
272
    if (PlatformBridge::layoutTestMode())
273
        return Color(0xff, 0xff, 0xcc); // Pale yellow.
274
    COLORREF color = GetSysColor(COLOR_HIGHLIGHTTEXT);
275
    return Color(GetRValue(color), GetGValue(color), GetBValue(color), 0xff);
276
277
278
279
280
281
282
}

Color RenderThemeChromiumWin::platformInactiveSelectionForegroundColor() const
{
    return Color::white;
}

283
284
Color RenderThemeChromiumWin::platformActiveTextSearchHighlightColor() const
{
285
    return Color(0xff, 0x96, 0x32); // Orange.
286
287
288
}

Color RenderThemeChromiumWin::platformInactiveTextSearchHighlightColor() const
289
{
290
    return Color(0xff, 0xff, 0x96); // Yellow.
291
292
}

293
void RenderThemeChromiumWin::systemFont(int propId, FontDescription& fontDescription) const
294
295
{
    // This logic owes much to RenderThemeSafari.cpp.
296
297
    FontDescription* cachedDesc = 0;
    AtomicString faceName;
298
299
300
301
302
303
304
    float fontSize = 0;
    switch (propId) {
    case CSSValueSmallCaption:
        cachedDesc = &smallSystemFont;
        if (!smallSystemFont.isAbsoluteSize()) {
            NONCLIENTMETRICS metrics;
            getNonClientMetrics(&metrics);
305
            faceName = AtomicString(metrics.lfSmCaptionFont.lfFaceName, wcslen(metrics.lfSmCaptionFont.lfFaceName));
306
307
308
309
310
311
312
313
            fontSize = systemFontSize(metrics.lfSmCaptionFont);
        }
        break;
    case CSSValueMenu:
        cachedDesc = &menuFont;
        if (!menuFont.isAbsoluteSize()) {
            NONCLIENTMETRICS metrics;
            getNonClientMetrics(&metrics);
314
            faceName = AtomicString(metrics.lfMenuFont.lfFaceName, wcslen(metrics.lfMenuFont.lfFaceName));
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
            fontSize = systemFontSize(metrics.lfMenuFont);
        }
        break;
    case CSSValueStatusBar:
        cachedDesc = &labelFont;
        if (!labelFont.isAbsoluteSize()) {
            NONCLIENTMETRICS metrics;
            getNonClientMetrics(&metrics);
            faceName = metrics.lfStatusFont.lfFaceName;
            fontSize = systemFontSize(metrics.lfStatusFont);
        }
        break;
    case CSSValueWebkitMiniControl:
    case CSSValueWebkitSmallControl:
    case CSSValueWebkitControl:
330
        faceName = defaultGUIFont();
331
332
333
334
        // Why 2 points smaller?  Because that's what Gecko does.
        fontSize = defaultFontSize - pointsToPixels(2);
        break;
    default:
335
        faceName = defaultGUIFont();
336
337
338
339
340
341
342
343
        fontSize = defaultFontSize;
        break;
    }

    if (!cachedDesc)
        cachedDesc = &fontDescription;

    if (fontSize) {
344
        cachedDesc->firstFamily().setFamily(faceName);
345
346
347
348
349
350
351
352
353
        cachedDesc->setIsAbsoluteSize(true);
        cachedDesc->setGenericFamily(FontDescription::NoFamily);
        cachedDesc->setSpecifiedSize(fontSize);
        cachedDesc->setWeight(FontWeightNormal);
        cachedDesc->setItalic(false);
    }
    fontDescription = *cachedDesc;
}

354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
// Map a CSSValue* system color to an index understood by GetSysColor().
static int cssValueIdToSysColorIndex(int cssValueId)
{
    switch (cssValueId) {
    case CSSValueActiveborder: return COLOR_ACTIVEBORDER;
    case CSSValueActivecaption: return COLOR_ACTIVECAPTION;
    case CSSValueAppworkspace: return COLOR_APPWORKSPACE;
    case CSSValueBackground: return COLOR_BACKGROUND;
    case CSSValueButtonface: return COLOR_BTNFACE;
    case CSSValueButtonhighlight: return COLOR_BTNHIGHLIGHT;
    case CSSValueButtonshadow: return COLOR_BTNSHADOW;
    case CSSValueButtontext: return COLOR_BTNTEXT;
    case CSSValueCaptiontext: return COLOR_CAPTIONTEXT;
    case CSSValueGraytext: return COLOR_GRAYTEXT;
    case CSSValueHighlight: return COLOR_HIGHLIGHT;
    case CSSValueHighlighttext: return COLOR_HIGHLIGHTTEXT;
    case CSSValueInactiveborder: return COLOR_INACTIVEBORDER;
    case CSSValueInactivecaption: return COLOR_INACTIVECAPTION;
    case CSSValueInactivecaptiontext: return COLOR_INACTIVECAPTIONTEXT;
    case CSSValueInfobackground: return COLOR_INFOBK;
    case CSSValueInfotext: return COLOR_INFOTEXT;
    case CSSValueMenu: return COLOR_MENU;
    case CSSValueMenutext: return COLOR_MENUTEXT;
    case CSSValueScrollbar: return COLOR_SCROLLBAR;
    case CSSValueThreeddarkshadow: return COLOR_3DDKSHADOW;
    case CSSValueThreedface: return COLOR_3DFACE;
    case CSSValueThreedhighlight: return COLOR_3DHIGHLIGHT;
    case CSSValueThreedlightshadow: return COLOR_3DLIGHT;
    case CSSValueThreedshadow: return COLOR_3DSHADOW;
    case CSSValueWindow: return COLOR_WINDOW;
    case CSSValueWindowframe: return COLOR_WINDOWFRAME;
    case CSSValueWindowtext: return COLOR_WINDOWTEXT;
    default: return -1; // Unsupported CSSValue
    }
}

Color RenderThemeChromiumWin::systemColor(int cssValueId) const
{
    int sysColorIndex = cssValueIdToSysColorIndex(cssValueId);
393
    if (PlatformBridge::layoutTestMode() || (sysColorIndex == -1))
394
395
396
397
398
399
        return RenderTheme::systemColor(cssValueId);

    COLORREF color = GetSysColor(sysColorIndex);
    return Color(GetRValue(color), GetGValue(color), GetBValue(color));
}

400
401
402
403
404
void RenderThemeChromiumWin::adjustSliderThumbSize(RenderObject* o) const
{
    // These sizes match what WinXP draws for various menus.
    const int sliderThumbAlongAxis = 11;
    const int sliderThumbAcrossAxis = 21;
405
    if (o->style()->appearance() == SliderThumbHorizontalPart) {
406
407
408
409
410
        o->style()->setWidth(Length(sliderThumbAlongAxis, Fixed));
        o->style()->setHeight(Length(sliderThumbAcrossAxis, Fixed));
    } else if (o->style()->appearance() == SliderThumbVerticalPart) {
        o->style()->setWidth(Length(sliderThumbAcrossAxis, Fixed));
        o->style()->setHeight(Length(sliderThumbAlongAxis, Fixed));
411
412
    } else
        RenderThemeChromiumSkia::adjustSliderThumbSize(o);
413
414
}

415
bool RenderThemeChromiumWin::paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& r)
416
{
417
    return paintButton(o, i, r);
418
}
419
bool RenderThemeChromiumWin::paintRadio(RenderObject* o, const PaintInfo& i, const IntRect& r)
420
{
421
    return paintButton(o, i, r);
422
423
}

424
bool RenderThemeChromiumWin::paintButton(RenderObject* o, const PaintInfo& i, const IntRect& r)
425
426
427
{
    const ThemeData& themeData = getThemeData(o);

428
    ThemePainter painter(i.context, r);
429
    PlatformBridge::paintButton(painter.context(),
430
431
432
                                themeData.m_part,
                                themeData.m_state,
                                themeData.m_classicState,
433
                                painter.drawRect());
434
435
436
    return false;
}

437
bool RenderThemeChromiumWin::paintTextField(RenderObject* o, const PaintInfo& i, const IntRect& r)
438
439
440
441
{
    return paintTextFieldInternal(o, i, r, true);
}

442
bool RenderThemeChromiumWin::paintSliderTrack(RenderObject* o, const PaintInfo& i, const IntRect& r)
443
444
445
{
    const ThemeData& themeData = getThemeData(o);

446
    ThemePainter painter(i.context, r);
447
    PlatformBridge::paintTrackbar(painter.context(),
448
449
450
451
452
453
454
                                  themeData.m_part,
                                  themeData.m_state,
                                  themeData.m_classicState,
                                  painter.drawRect());
    return false;
}

455
bool RenderThemeChromiumWin::paintSliderThumb(RenderObject* o, const PaintInfo& i, const IntRect& r)
456
{
457
    return paintSliderTrack(o, i, r);
458
459
}

460
461
static int menuListButtonWidth()
{
462
    static int width = PlatformBridge::layoutTestMode() ? kStandardMenuListButtonWidth : GetSystemMetrics(SM_CXVSCROLL);
463
464
465
    return width;
}

466
// Used to paint unstyled menulists (i.e. with the default border)
467
bool RenderThemeChromiumWin::paintMenuList(RenderObject* o, const PaintInfo& i, const IntRect& r)
468
{
469
470
471
472
473
474
475
476
    if (!o->isBox())
        return false;

    const RenderBox* box = toRenderBox(o);
    int borderRight = box->borderRight();
    int borderLeft = box->borderLeft();
    int borderTop = box->borderTop();
    int borderBottom = box->borderBottom();
477
478
479
480
481
482

    // If all the borders are 0, then tell skia not to paint the border on the
    // textfield.  FIXME: http://b/1210017 Figure out how to get Windows to not
    // draw individual borders and then pass that to skia so we can avoid
    // drawing any borders that are set to 0. For non-zero borders, we draw the
    // border, but webkit just draws over it.
483
    bool drawEdges = !(!borderRight && !borderLeft && !borderTop && !borderBottom);
484
485
486
487
488
489

    paintTextFieldInternal(o, i, r, drawEdges);

    // Take padding and border into account.  If the MenuList is smaller than
    // the size of a button, make sure to shrink it appropriately and not put
    // its x position to the left of the menulist.
490
    const int buttonWidth = menuListButtonWidth();
491
492
493
494
    int spacingLeft = borderLeft + box->paddingLeft();
    int spacingRight = borderRight + box->paddingRight();
    int spacingTop = borderTop + box->paddingTop();
    int spacingBottom = borderBottom + box->paddingBottom();
495
496

    int buttonX;
497
    if (r.maxX() - r.x() < buttonWidth)
498
499
        buttonX = r.x();
    else
500
        buttonX = o->style()->direction() == LTR ? r.maxX() - spacingRight - buttonWidth : r.x() + spacingLeft;
501
502
503
504

    // Compute the rectangle of the button in the destination image.
    IntRect rect(buttonX,
                 r.y() + spacingTop,
505
                 std::min(buttonWidth, r.maxX() - r.x()),
506
507
508
                 r.height() - (spacingTop + spacingBottom));

    // Get the correct theme data for a textfield and paint the menu.
509
    ThemePainter painter(i.context, rect);
510
    PlatformBridge::paintMenuList(painter.context(),
511
512
513
                                  CP_DROPDOWNBUTTON,
                                  determineState(o),
                                  determineClassicState(o),
514
                                  painter.drawRect());
515
516
517
518
    return false;
}

// static
519
520
void RenderThemeChromiumWin::setDefaultFontSize(int fontSize)
{
521
    RenderThemeChromiumSkia::setDefaultFontSize(fontSize);
522
523
524
525
526

    // Reset cached fonts.
    smallSystemFont = menuFont = labelFont = FontDescription();
}

527
528
529
530
531
532
533
double RenderThemeChromiumWin::caretBlinkIntervalInternal() const
{
    // This involves a system call, so we cache the result.
    static double blinkInterval = querySystemBlinkInterval(RenderTheme::caretBlinkInterval());
    return blinkInterval;
}

534
unsigned RenderThemeChromiumWin::determineState(RenderObject* o, ControlSubPart subPart)
535
536
537
538
539
{
    unsigned result = TS_NORMAL;
    ControlPart appearance = o->style()->appearance();
    if (!isEnabled(o))
        result = TS_DISABLED;
540
541
542
543
    else if (isReadOnlyControl(o))
        result = (appearance == TextFieldPart || appearance == TextAreaPart || appearance == SearchFieldPart) ? ETS_READONLY : TS_DISABLED;
    // Active overrides hover and focused.
    else if (isPressed(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartPressed(o))
544
545
546
        result = TS_PRESSED;
    else if (supportsFocus(appearance) && isFocused(o))
        result = ETS_FOCUSED;
547
    else if (isHovered(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartHovered(o))
548
        result = TS_HOT;
549
550
551
552
553
554
555
556

    // CBS_UNCHECKED*: 1-4
    // CBS_CHECKED*: 5-8
    // CBS_MIXED*: 9-12
    if (isIndeterminate(o))
        result += 8;
    else if (isChecked(o))
        result += 4;
557
558
559
    return result;
}

560
561
562
563
564
565
566
unsigned RenderThemeChromiumWin::determineSliderThumbState(RenderObject* o)
{
    unsigned result = TUS_NORMAL;
    if (!isEnabled(o->parent()))
        result = TUS_DISABLED;
    else if (supportsFocus(o->style()->appearance()) && isFocused(o->parent()))
        result = TUS_FOCUSED;
567
    else if (toRenderSlider(o->parent())->inDragMode())
568
569
570
571
572
573
        result = TUS_PRESSED;
    else if (isHovered(o))
        result = TUS_HOT;
    return result;
}

574
unsigned RenderThemeChromiumWin::determineClassicState(RenderObject* o, ControlSubPart subPart)
575
576
{
    unsigned result = 0;
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595

    ControlPart part = o->style()->appearance();

    // Sliders are always in the normal state.
    if (part == SliderHorizontalPart || part == SliderVerticalPart)
        return result;

    // So are readonly text fields.
    if (isReadOnlyControl(o) && (part == TextFieldPart || part == TextAreaPart || part == SearchFieldPart))
        return result;   

    if (part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart) {
        if (!isEnabled(o->parent()))
            result = DFCS_INACTIVE;
        else if (toRenderSlider(o->parent())->inDragMode()) // Active supersedes hover
            result = DFCS_PUSHED;
        else if (isHovered(o))
            result = DFCS_HOT;
    } else {
596
        if (!isEnabled(o) || isReadOnlyControl(o))
597
            result = DFCS_INACTIVE;
598
599
        // Active supersedes hover
        else if (isPressed(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartPressed(o))
600
601
602
            result = DFCS_PUSHED;
        else if (supportsFocus(part) && isFocused(o)) // So does focused
            result = 0;
603
        else if (isHovered(o) && (subPart == SpinButtonUp) == isSpinUpButtonPartHovered(o))
604
            result = DFCS_HOT;
605
606
        // Classic theme can't represent indeterminate states. Use unchecked appearance.
        if (isChecked(o) && !isIndeterminate(o))
607
608
            result |= DFCS_CHECKED;
    }
609
610
611
    return result;
}

612
ThemeData RenderThemeChromiumWin::getThemeData(RenderObject* o, ControlSubPart subPart)
613
614
615
616
617
{
    ThemeData result;
    switch (o->style()->appearance()) {
    case CheckboxPart:
        result.m_part = BP_CHECKBOX;
618
        result.m_state = determineState(o);
619
620
621
622
        result.m_classicState = DFCS_BUTTONCHECK;
        break;
    case RadioPart:
        result.m_part = BP_RADIOBUTTON;
623
        result.m_state = determineState(o);
624
625
        result.m_classicState = DFCS_BUTTONRADIO;
        break;
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
    case PushButtonPart:
    case ButtonPart:
        result.m_part = BP_PUSHBUTTON;
        result.m_state = determineState(o);
        result.m_classicState = DFCS_BUTTONPUSH;
        break;
    case SliderHorizontalPart:
        result.m_part = TKP_TRACK;
        result.m_state = TRS_NORMAL;
        break;
    case SliderVerticalPart:
        result.m_part = TKP_TRACKVERT;
        result.m_state = TRVS_NORMAL;
        break;
    case SliderThumbHorizontalPart:
        result.m_part = TKP_THUMBBOTTOM;
        result.m_state = determineSliderThumbState(o);
        break;
    case SliderThumbVerticalPart:
        result.m_part = TKP_THUMBVERT;
        result.m_state = determineSliderThumbState(o);
        break;
648
649
    case ListboxPart:
    case MenulistPart:
650
    case MenulistButtonPart:
651
    case SearchFieldPart:
652
653
    case TextFieldPart:
    case TextAreaPart:
654
655
        result.m_part = EP_EDITTEXT;
        result.m_state = determineState(o);
656
        break;
657
    case InnerSpinButtonPart:
658
        result.m_part = subPart == SpinButtonUp ? SPNP_UP : SPNP_DOWN;
659
660
661
        result.m_state = determineState(o, subPart);
        result.m_classicState = subPart == SpinButtonUp ? DFCS_SCROLLUP : DFCS_SCROLLDOWN;
        break;
662
663
    }

664
    result.m_classicState |= determineClassicState(o, subPart);
665
666
667
668
669

    return result;
}

bool RenderThemeChromiumWin::paintTextFieldInternal(RenderObject* o,
670
                                                    const PaintInfo& i,
671
672
                                                    const IntRect& r,
                                                    bool drawEdges)
673
{
674
    // Fallback to white if the specified color object is invalid.
675
    // (Note PlatformBridge::paintTextField duplicates this check).
676
    Color backgroundColor(Color::white);
677
678
    if (o->style()->visitedDependentColor(CSSPropertyBackgroundColor).isValid())
        backgroundColor = o->style()->visitedDependentColor(CSSPropertyBackgroundColor);
679
680
681
682
683
684
685
686

    // If we have background-image, don't fill the content area to expose the
    // parent's background. Also, we shouldn't fill the content area if the
    // alpha of the color is 0. The API of Windows GDI ignores the alpha.
    //
    // Note that we should paint the content area white if we have neither the
    // background color nor background image explicitly specified to keep the
    // appearance of select element consistent with other browsers.
687
688
689
690
691
692
693
    bool fillContentArea = !o->style()->hasBackgroundImage() && backgroundColor.alpha();

    if (o->style()->hasBorderRadius()) {
        // If the style has rounded borders, setup the context to clip the
        // background (themed or filled) appropriately.
        // FIXME: make sure we do the right thing if css background-clip is set.
        i.context->save();
694
        i.context->addRoundedRectClip(o->style()->getRoundedBorderFor(r));
695
696
697
    }
    {
        const ThemeData& themeData = getThemeData(o);
698
        ThemePainter painter(i.context, r);
699
        PlatformBridge::paintTextField(painter.context(),
700
701
702
703
704
705
706
707
708
709
710
                                       themeData.m_part,
                                       themeData.m_state,
                                       themeData.m_classicState,
                                       painter.drawRect(),
                                       backgroundColor,
                                       fillContentArea,
                                       drawEdges);
        // End of block commits the painter before restoring context.
    }
    if (o->style()->hasBorderRadius())
        i.context->restore();
711
712
713
    return false;
}

714
715
716
717
718
719
720
721
722
723
724
void RenderThemeChromiumWin::adjustInnerSpinButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
{
    int width = ScrollbarTheme::nativeTheme()->scrollbarThickness();
    style->setWidth(Length(width, Fixed));
    style->setMinWidth(Length(width, Fixed));
}

bool RenderThemeChromiumWin::paintInnerSpinButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
{
    IntRect half = rect;

725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
    // Need explicit blocks to avoid to create multiple ThemePainter instances.
    {
        half.setHeight(rect.height() / 2);
        const ThemeData& upThemeData = getThemeData(object, SpinButtonUp);
        ThemePainter upPainter(info.context, half);
        PlatformBridge::paintSpinButton(upPainter.context(),
                                        upThemeData.m_part,
                                        upThemeData.m_state,
                                        upThemeData.m_classicState,
                                        upPainter.drawRect());
    }

    {
        half.setY(rect.y() + rect.height() / 2);
        const ThemeData& downThemeData = getThemeData(object, SpinButtonDown);
        ThemePainter downPainter(info.context, half);
        PlatformBridge::paintSpinButton(downPainter.context(),
                                        downThemeData.m_part,
                                        downThemeData.m_state,
                                        downThemeData.m_classicState,
                                        downPainter.drawRect());
    }
747
748
749
    return false;
}

750
751
752
753
754
755
756
757
758
759
760
761
762
#if ENABLE(PROGRESS_TAG)

// MSDN says that update intervals for the bar is 30ms.
// http://msdn.microsoft.com/en-us/library/bb760842(v=VS.85).aspx
static const double progressAnimationFrameRate = 0.033;

double RenderThemeChromiumWin::animationRepeatIntervalForProgressBar(RenderProgress*) const
{
    return progressAnimationFrameRate;
}

double RenderThemeChromiumWin::animationDurationForProgressBar(RenderProgress* renderProgress) const
{
763
764
765
    // On Chromium Windows port, animationProgress() and associated values aren't used.
    // So here we can return arbitrary positive value.
    return progressAnimationFrameRate;
766
767
768
769
770
771
}

void RenderThemeChromiumWin::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle*, Element*) const
{
}

772
bool RenderThemeChromiumWin::paintProgressBar(RenderObject* o, const PaintInfo& i, const IntRect& r)
773
{
774
    if (!o->isProgress())
775
776
        return true;

777
    RenderProgress* renderProgress = toRenderProgress(o);
778
779
    // For indeterminate bar, valueRect is ignored and it is computed by the theme engine
    // because the animation is a platform detail and WebKit doesn't need to know how.
780
    IntRect valueRect = renderProgress->isDeterminate() ? determinateProgressValueRectFor(renderProgress, r) : IntRect(0, 0, 0, 0);
781
    double animatedSeconds = renderProgress->animationStartTime() ?  WTF::currentTime() - renderProgress->animationStartTime() : 0;
782
    ThemePainter painter(i.context, r);
783
    PlatformBridge::paintProgressBar(painter.context(), r, valueRect, renderProgress->isDeterminate(), animatedSeconds);
784
    return false;
785
786
787
788
}

#endif

789
} // namespace WebCore