WebKitTools/DumpRenderTree/chromium/WebThemeControlDRT.cpp
changeset 2 303757a437d3
parent 0 4f2f89ce4247
equal deleted inserted replaced
0:4f2f89ce4247 2:303757a437d3
     1 /*
       
     2  * Copyright (C) 2010 Google Inc. All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions are
       
     6  * met:
       
     7  *
       
     8  *     * Redistributions of source code must retain the above copyright
       
     9  * notice, this list of conditions and the following disclaimer.
       
    10  *     * Redistributions in binary form must reproduce the above
       
    11  * copyright notice, this list of conditions and the following disclaimer
       
    12  * in the documentation and/or other materials provided with the
       
    13  * distribution.
       
    14  *     * Neither the name of Google Inc. nor the names of its
       
    15  * contributors may be used to endorse or promote products derived from
       
    16  * this software without specific prior written permission.
       
    17  *
       
    18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
       
    19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
       
    20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
       
    21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
       
    22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
       
    23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
       
    24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
       
    25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
       
    26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       
    28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    29  */
       
    30 
       
    31 // This file implements a simple generic version of the WebThemeEngine,
       
    32 // which is used to draw all the native controls on a web page. We use this
       
    33 // file when running in layout test mode in order to remove any
       
    34 // platform-specific rendering differences due to themes, colors, etc.
       
    35 //
       
    36 
       
    37 #include "config.h"
       
    38 #include "WebThemeControlDRT.h"
       
    39 
       
    40 #include "skia/ext/platform_canvas.h"
       
    41 #include "skia/ext/skia_utils_win.h"
       
    42 #include "third_party/skia/include/core/SkPaint.h"
       
    43 #include "third_party/skia/include/core/SkPath.h"
       
    44 #include "third_party/skia/include/core/SkRect.h"
       
    45 
       
    46 #include <wtf/Assertions.h>
       
    47 
       
    48 using namespace std;
       
    49 using namespace skia;
       
    50 
       
    51 static const SkColor edgeColor     = SK_ColorBLACK;
       
    52 static const SkColor readOnlyColor = SkColorSetRGB(0xe9, 0xc2, 0xa6);
       
    53 static const SkColor fgColor       = SK_ColorBLACK;
       
    54 static const SkColor bgColors[]    = {
       
    55     SK_ColorBLACK,                   // Unknown
       
    56     SkColorSetRGB(0xc9, 0xc9, 0xc9), // Disabled
       
    57     SkColorSetRGB(0xf3, 0xe0, 0xd0), // Readonly
       
    58     SkColorSetRGB(0x89, 0xc4, 0xff), // Normal
       
    59     SkColorSetRGB(0x43, 0xf9, 0xff), // Hot
       
    60     SkColorSetRGB(0x20, 0xf6, 0xcc), // Focused
       
    61     SkColorSetRGB(0x00, 0xf3, 0xac), // Hover
       
    62     SkColorSetRGB(0xa9, 0xff, 0x12), // Pressed
       
    63     SkColorSetRGB(0xcc, 0xcc, 0xcc)  // Indeterminate
       
    64 };
       
    65 
       
    66 static SkIRect validate(const SkIRect& rect, WebThemeControlDRT::Type ctype)
       
    67 {
       
    68     switch (ctype) {
       
    69     case WebThemeControlDRT::UncheckedBoxType:
       
    70     case WebThemeControlDRT::CheckedBoxType:
       
    71     case WebThemeControlDRT::UncheckedRadioType:
       
    72     case WebThemeControlDRT::CheckedRadioType: {
       
    73         SkIRect retval = rect;
       
    74 
       
    75         // The maximum width and height is 13.
       
    76         // Center the square in the passed rectangle.
       
    77         const int maxControlSize = 13;
       
    78         int controlSize = min(rect.width(), rect.height());
       
    79         controlSize = min(controlSize, maxControlSize);
       
    80 
       
    81         retval.fLeft   = rect.fLeft + (rect.width() / 2) - (controlSize / 2);
       
    82         retval.fRight  = retval.fLeft + controlSize - 1;
       
    83         retval.fTop    = rect.fTop + (rect.height() / 2) - (controlSize / 2);
       
    84         retval.fBottom = retval.fTop + controlSize - 1;
       
    85 
       
    86         return retval;
       
    87     }
       
    88 
       
    89     default:
       
    90         return rect;
       
    91     }
       
    92 }
       
    93 
       
    94 // WebThemeControlDRT
       
    95 
       
    96 WebThemeControlDRT::WebThemeControlDRT(PlatformCanvas* canvas,
       
    97                                        const SkIRect& irect,
       
    98                                        Type ctype,
       
    99                                        State cstate)
       
   100     : m_canvas(canvas)
       
   101     , m_irect(validate(irect, ctype))
       
   102     , m_type(ctype)
       
   103     , m_state(cstate)
       
   104     , m_left(m_irect.fLeft)
       
   105     , m_right(m_irect.fRight)
       
   106     , m_top(m_irect.fTop)
       
   107     , m_bottom(m_irect.fBottom)
       
   108     , m_height(m_irect.height())
       
   109     , m_width(m_irect.width())
       
   110     , m_edgeColor(edgeColor)
       
   111     , m_bgColor(bgColors[cstate])
       
   112     , m_fgColor(fgColor)
       
   113 {
       
   114 }
       
   115 
       
   116 WebThemeControlDRT::~WebThemeControlDRT()
       
   117 {
       
   118 }
       
   119 
       
   120 void WebThemeControlDRT::box(const SkIRect& rect, SkColor fillColor)
       
   121 {
       
   122     SkPaint paint;
       
   123 
       
   124     paint.setStyle(SkPaint::kFill_Style);
       
   125     paint.setColor(fillColor);
       
   126     m_canvas->drawIRect(rect, paint);
       
   127 
       
   128     paint.setColor(m_edgeColor);
       
   129     paint.setStyle(SkPaint::kStroke_Style);
       
   130     m_canvas->drawIRect(rect, paint);
       
   131 }
       
   132 
       
   133 void WebThemeControlDRT::line(int x0, int y0, int x1, int y1, SkColor color)
       
   134 {
       
   135     SkPaint paint;
       
   136     paint.setColor(color);
       
   137     m_canvas->drawLine(SkIntToScalar(x0), SkIntToScalar(y0),
       
   138                        SkIntToScalar(x1), SkIntToScalar(y1),
       
   139                        paint);
       
   140 }
       
   141 
       
   142 void WebThemeControlDRT::triangle(int x0, int y0,
       
   143                                   int x1, int y1,
       
   144                                   int x2, int y2,
       
   145                                   SkColor color)
       
   146 {
       
   147     SkPath path;
       
   148     SkPaint paint;
       
   149 
       
   150     paint.setColor(color);
       
   151     paint.setStyle(SkPaint::kFill_Style);
       
   152     path.incReserve(4);
       
   153     path.moveTo(SkIntToScalar(x0), SkIntToScalar(y0));
       
   154     path.lineTo(SkIntToScalar(x1), SkIntToScalar(y1));
       
   155     path.lineTo(SkIntToScalar(x2), SkIntToScalar(y2));
       
   156     path.close();
       
   157     m_canvas->drawPath(path, paint);
       
   158 
       
   159     paint.setColor(m_edgeColor);
       
   160     paint.setStyle(SkPaint::kStroke_Style);
       
   161     m_canvas->drawPath(path, paint);
       
   162 }
       
   163 
       
   164 void WebThemeControlDRT::roundRect(SkColor color)
       
   165 {
       
   166     SkRect rect;
       
   167     SkScalar radius = SkIntToScalar(5);
       
   168     SkPaint paint;
       
   169 
       
   170     rect.set(m_irect);
       
   171     paint.setColor(color);
       
   172     paint.setStyle(SkPaint::kFill_Style);
       
   173     m_canvas->drawRoundRect(rect, radius, radius, paint);
       
   174 
       
   175     paint.setColor(m_edgeColor);
       
   176     paint.setStyle(SkPaint::kStroke_Style);
       
   177     m_canvas->drawRoundRect(rect, radius, radius, paint);
       
   178 }
       
   179 
       
   180 void WebThemeControlDRT::oval(SkColor color)
       
   181 {
       
   182     SkRect rect;
       
   183     SkPaint paint;
       
   184 
       
   185     rect.set(m_irect);
       
   186     paint.setColor(color);
       
   187     paint.setStyle(SkPaint::kFill_Style);
       
   188     m_canvas->drawOval(rect, paint);
       
   189 
       
   190     paint.setColor(m_edgeColor);
       
   191     paint.setStyle(SkPaint::kStroke_Style);
       
   192     m_canvas->drawOval(rect, paint);
       
   193 }
       
   194 
       
   195 void WebThemeControlDRT::circle(SkScalar radius, SkColor color)
       
   196 {
       
   197     SkScalar cy = SkIntToScalar(m_top  + m_height / 2);
       
   198     SkScalar cx = SkIntToScalar(m_left + m_width / 2);
       
   199     SkPaint paint;
       
   200 
       
   201     paint.setColor(color);
       
   202     paint.setStyle(SkPaint::kFill_Style);
       
   203     m_canvas->drawCircle(cx, cy, radius, paint);
       
   204 
       
   205     paint.setColor(m_edgeColor);
       
   206     paint.setStyle(SkPaint::kStroke_Style);
       
   207     m_canvas->drawCircle(cx, cy, radius, paint);
       
   208 }
       
   209 
       
   210 void WebThemeControlDRT::nestedBoxes(int indentLeft,
       
   211                                      int indentTop,
       
   212                                      int indentRight,
       
   213                                      int indentBottom,
       
   214                                      SkColor outerColor,
       
   215                                      SkColor innerColor)
       
   216 {
       
   217     SkIRect lirect;
       
   218     box(m_irect, outerColor);
       
   219     lirect.set(m_irect.fLeft + indentLeft,
       
   220                m_irect.fTop + indentTop,
       
   221                m_irect.fRight - indentRight,
       
   222                m_irect.fBottom - indentBottom);
       
   223     box(lirect, innerColor);
       
   224 }
       
   225 
       
   226 void WebThemeControlDRT::markState()
       
   227 {
       
   228     // The horizontal lines in a read only control are spaced by this amount.
       
   229     const int readOnlyLineOffset = 5;
       
   230 
       
   231     // The length of a triangle side for the corner marks.
       
   232     const int triangleSize = 5;
       
   233 
       
   234     switch (m_state) {
       
   235     case UnknownState:
       
   236     case DisabledState:
       
   237     case NormalState:
       
   238         // Don't visually mark these states (color is enough).
       
   239         break;
       
   240     case ReadOnlyState:
       
   241         // Drawing lines across the control.
       
   242         for (int i = m_top + readOnlyLineOffset; i < m_bottom; i += readOnlyLineOffset)
       
   243             line(m_left + 1, i, m_right - 1, i, readOnlyColor);
       
   244         break;
       
   245 
       
   246     case HotState:
       
   247         // Draw a triangle in the upper left corner of the control.
       
   248         triangle(m_left,                 m_top,
       
   249                  m_left + triangleSize,  m_top,
       
   250                  m_left,                 m_top + triangleSize,    m_edgeColor);
       
   251         break;
       
   252 
       
   253     case HoverState:
       
   254         // Draw a triangle in the upper right corner of the control.
       
   255         triangle(m_right,                m_top,
       
   256                  m_right,                m_top + triangleSize,
       
   257                  m_right - triangleSize, m_top,                   m_edgeColor);
       
   258         break;
       
   259 
       
   260     case FocusedState:
       
   261         // Draw a triangle in the bottom right corner of the control.
       
   262         triangle(m_right,                m_bottom,
       
   263                  m_right - triangleSize, m_bottom,
       
   264                  m_right,                m_bottom - triangleSize, m_edgeColor);
       
   265         break;
       
   266 
       
   267     case PressedState:
       
   268         // Draw a triangle in the bottom left corner of the control.
       
   269         triangle(m_left,                 m_bottom,
       
   270                  m_left,                 m_bottom - triangleSize,
       
   271                  m_left + triangleSize,  m_bottom,                m_edgeColor);
       
   272         break;
       
   273 
       
   274     default:
       
   275         ASSERT_NOT_REACHED();
       
   276         CRASH();
       
   277         break;
       
   278     }
       
   279 }
       
   280 
       
   281 void WebThemeControlDRT::draw()
       
   282 {
       
   283     int halfWidth = m_width / 2;
       
   284     int halfHeight = m_height / 2;
       
   285     int quarterWidth = m_width / 4;
       
   286     int quarterHeight = m_height / 4;
       
   287 
       
   288     // Indent amounts for the check in a checkbox or radio button.
       
   289     const int checkIndent = 3;
       
   290 
       
   291     // Indent amounts for short and long sides of the scrollbar notches.
       
   292     const int notchLongOffset = 1;
       
   293     const int notchShortOffset = 4;
       
   294     const int noOffset = 0;
       
   295 
       
   296     // Indent amounts for the short and long sides of a scroll thumb box.
       
   297     const int thumbLongIndent = 0;
       
   298     const int thumbShortIndent = 2;
       
   299 
       
   300     // Indents for the crosshatch on a scroll grip.
       
   301     const int gripLongIndent = 3;
       
   302     const int gripShortIndent = 5;
       
   303 
       
   304     // Indents for the the slider track.
       
   305     const int sliderIndent = 2;
       
   306 
       
   307     m_canvas->beginPlatformPaint();
       
   308 
       
   309     switch (m_type) {
       
   310     case UnknownType:
       
   311         ASSERT_NOT_REACHED();
       
   312         CRASH();
       
   313         break;
       
   314 
       
   315     case TextFieldType:
       
   316         // We render this by hand outside of this function.
       
   317         ASSERT_NOT_REACHED();
       
   318         CRASH();
       
   319         break;
       
   320 
       
   321     case PushButtonType:
       
   322         // push buttons render as a rounded rectangle
       
   323         roundRect(m_bgColor);
       
   324         break;
       
   325 
       
   326     case UncheckedBoxType:
       
   327         // Unchecked boxes are simply plain boxes.
       
   328         box(m_irect, m_bgColor);
       
   329         break;
       
   330 
       
   331     case CheckedBoxType:
       
   332         nestedBoxes(checkIndent, checkIndent, checkIndent, checkIndent, m_bgColor, m_fgColor);
       
   333         break;
       
   334 
       
   335     case IndeterminateCheckboxType:
       
   336         // Indeterminate checkbox is a box containing '-'.
       
   337         nestedBoxes(checkIndent, halfHeight, checkIndent, halfHeight, m_bgColor, m_fgColor);
       
   338         break;
       
   339 
       
   340     case UncheckedRadioType:
       
   341         circle(SkIntToScalar(halfHeight), m_bgColor);
       
   342         break;
       
   343 
       
   344     case CheckedRadioType:
       
   345         circle(SkIntToScalar(halfHeight), m_bgColor);
       
   346         circle(SkIntToScalar(halfHeight - checkIndent), m_fgColor);
       
   347         break;
       
   348 
       
   349     case HorizontalScrollTrackBackType: {
       
   350         // Draw a box with a notch at the left.
       
   351         int longOffset = halfHeight - notchLongOffset;
       
   352         int shortOffset = m_width - notchShortOffset;
       
   353         nestedBoxes(noOffset, longOffset, shortOffset, longOffset, m_bgColor, m_edgeColor);
       
   354         break;
       
   355     }
       
   356 
       
   357     case HorizontalScrollTrackForwardType: {
       
   358         // Draw a box with a notch at the right.
       
   359         int longOffset  = halfHeight - notchLongOffset;
       
   360         int shortOffset = m_width - notchShortOffset;
       
   361         nestedBoxes(shortOffset, longOffset, noOffset, longOffset, m_bgColor, m_fgColor);
       
   362         break;
       
   363     }
       
   364 
       
   365     case VerticalScrollTrackBackType: {
       
   366         // Draw a box with a notch at the top.
       
   367         int longOffset  = halfWidth - notchLongOffset;
       
   368         int shortOffset = m_height - notchShortOffset;
       
   369         nestedBoxes(longOffset, noOffset, longOffset, shortOffset, m_bgColor, m_fgColor);
       
   370         break;
       
   371     }
       
   372 
       
   373     case VerticalScrollTrackForwardType: {
       
   374         // Draw a box with a notch at the bottom.
       
   375         int longOffset  = halfWidth - notchLongOffset;
       
   376         int shortOffset = m_height - notchShortOffset;
       
   377         nestedBoxes(longOffset, shortOffset, longOffset, noOffset, m_bgColor, m_fgColor);
       
   378         break;
       
   379     }
       
   380 
       
   381     case HorizontalScrollThumbType:
       
   382         // Draw a narrower box on top of the outside box.
       
   383         nestedBoxes(thumbLongIndent, thumbShortIndent, thumbLongIndent, thumbShortIndent, m_bgColor, m_bgColor);
       
   384         break;
       
   385 
       
   386     case VerticalScrollThumbType:
       
   387         // Draw a shorter box on top of the outside box.
       
   388         nestedBoxes(thumbShortIndent, thumbLongIndent, thumbShortIndent, thumbLongIndent, m_bgColor, m_bgColor);
       
   389         break;
       
   390 
       
   391     case HorizontalSliderThumbType:
       
   392         // Slider thumbs are ovals.
       
   393         oval(m_bgColor);
       
   394         break;
       
   395 
       
   396     case HorizontalScrollGripType: {
       
   397         // Draw a horizontal crosshatch for the grip.
       
   398         int longOffset = halfWidth - gripLongIndent;
       
   399         line(m_left  + gripLongIndent, m_top    + halfHeight,
       
   400              m_right - gripLongIndent, m_top    + halfHeight,      m_fgColor);
       
   401         line(m_left  + longOffset,     m_top    + gripShortIndent,
       
   402              m_left  + longOffset,     m_bottom - gripShortIndent, m_fgColor);
       
   403         line(m_right - longOffset,     m_top    + gripShortIndent,
       
   404              m_right - longOffset,     m_bottom - gripShortIndent, m_fgColor);
       
   405         break;
       
   406     }
       
   407 
       
   408     case VerticalScrollGripType: {
       
   409         // Draw a vertical crosshatch for the grip.
       
   410         int longOffset = halfHeight - gripLongIndent;
       
   411         line(m_left  + halfWidth,       m_top    + gripLongIndent,
       
   412              m_left  + halfWidth,       m_bottom - gripLongIndent, m_fgColor);
       
   413         line(m_left  + gripShortIndent, m_top    + longOffset,
       
   414              m_right - gripShortIndent, m_top    + longOffset,     m_fgColor);
       
   415         line(m_left  + gripShortIndent, m_bottom - longOffset,
       
   416              m_right - gripShortIndent, m_bottom - longOffset,     m_fgColor);
       
   417         break;
       
   418     }
       
   419 
       
   420     case LeftArrowType:
       
   421         // Draw a left arrow inside a box.
       
   422         box(m_irect, m_bgColor);
       
   423         triangle(m_right - quarterWidth, m_top    + quarterHeight,
       
   424                  m_right - quarterWidth, m_bottom - quarterHeight,
       
   425                  m_left  + quarterWidth, m_top    + halfHeight,    m_fgColor);
       
   426         break;
       
   427 
       
   428     case RightArrowType:
       
   429         // Draw a left arrow inside a box.
       
   430         box(m_irect, m_bgColor);
       
   431         triangle(m_left  + quarterWidth, m_top    + quarterHeight,
       
   432                  m_right - quarterWidth, m_top    + halfHeight,
       
   433                  m_left  + quarterWidth, m_bottom - quarterHeight, m_fgColor);
       
   434         break;
       
   435 
       
   436     case UpArrowType:
       
   437         // Draw an up arrow inside a box.
       
   438         box(m_irect, m_bgColor);
       
   439         triangle(m_left  + quarterWidth, m_bottom - quarterHeight,
       
   440                  m_left  + halfWidth,    m_top    + quarterHeight,
       
   441                  m_right - quarterWidth, m_bottom - quarterHeight, m_fgColor);
       
   442         break;
       
   443 
       
   444     case DownArrowType:
       
   445         // Draw a down arrow inside a box.
       
   446         box(m_irect, m_bgColor);
       
   447         triangle(m_left  + quarterWidth, m_top    + quarterHeight,
       
   448                  m_right - quarterWidth, m_top    + quarterHeight,
       
   449                  m_left  + halfWidth,    m_bottom - quarterHeight, m_fgColor);
       
   450         break;
       
   451 
       
   452     case HorizontalSliderTrackType: {
       
   453         // Draw a narrow rect for the track plus box hatches on the ends.
       
   454         SkIRect lirect;
       
   455         lirect = m_irect;
       
   456         lirect.inset(noOffset, halfHeight - sliderIndent);
       
   457         box(lirect, m_bgColor);
       
   458         line(m_left,  m_top, m_left,  m_bottom, m_edgeColor);
       
   459         line(m_right, m_top, m_right, m_bottom, m_edgeColor);
       
   460         break;
       
   461     }
       
   462 
       
   463     case DropDownButtonType:
       
   464         // Draw a box with a big down arrow on top.
       
   465         box(m_irect, m_bgColor);
       
   466         triangle(m_left  + quarterWidth, m_top,
       
   467                  m_right - quarterWidth, m_top,
       
   468                  m_left  + halfWidth,    m_bottom, m_fgColor);
       
   469         break;
       
   470 
       
   471     default:
       
   472         ASSERT_NOT_REACHED();
       
   473         CRASH();
       
   474         break;
       
   475     }
       
   476 
       
   477     markState();
       
   478     m_canvas->endPlatformPaint();
       
   479 }
       
   480 
       
   481 // Because rendering a text field is dependent on input
       
   482 // parameters the other controls don't have, we render it directly
       
   483 // rather than trying to overcomplicate draw() further.
       
   484 void WebThemeControlDRT::drawTextField(bool drawEdges, bool fillContentArea, SkColor color)
       
   485 {
       
   486     SkPaint paint;
       
   487 
       
   488     m_canvas->beginPlatformPaint();
       
   489     if (fillContentArea) {
       
   490         paint.setColor(color);
       
   491         paint.setStyle(SkPaint::kFill_Style);
       
   492         m_canvas->drawIRect(m_irect, paint);
       
   493     }
       
   494     if (drawEdges) {
       
   495         paint.setColor(m_edgeColor);
       
   496         paint.setStyle(SkPaint::kStroke_Style);
       
   497         m_canvas->drawIRect(m_irect, paint);
       
   498     }
       
   499 
       
   500     markState();
       
   501     m_canvas->endPlatformPaint();
       
   502 }
       
   503 
       
   504 void WebThemeControlDRT::drawProgressBar(const SkIRect& fillRect)
       
   505 {
       
   506     SkPaint paint;
       
   507 
       
   508     m_canvas->beginPlatformPaint();
       
   509     paint.setColor(m_bgColor);
       
   510     paint.setStyle(SkPaint::kFill_Style);
       
   511     m_canvas->drawIRect(m_irect, paint);
       
   512 
       
   513     // Emulate clipping
       
   514     SkIRect tofill;
       
   515     tofill.intersect(m_irect, fillRect);
       
   516     paint.setColor(m_fgColor);
       
   517     paint.setStyle(SkPaint::kFill_Style);
       
   518     m_canvas->drawIRect(tofill, paint);
       
   519 
       
   520     markState();
       
   521     m_canvas->endPlatformPaint();
       
   522 }
       
   523