Home | History | Annotate | Download | only in android
      1 /*
      2  * Copyright 2006, The Android Open Source Project
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *  * Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  *  * Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "RenderSkinCombo.h"
     28 
     29 #include "CString.h"
     30 #include "Document.h"
     31 #include "Element.h"
     32 #include "Node.h"
     33 #include "NodeRenderStyle.h"
     34 #include "RenderStyle.h"
     35 #include "SkCanvas.h"
     36 #include "SkNinePatch.h"
     37 
     38 namespace WebCore {
     39 
     40 // Indicates if the entire asset is being drawn, or if the border is being
     41 // excluded and just the arrow drawn.
     42 enum BorderStyle {
     43     FullAsset,
     44     NoBorder
     45 };
     46 
     47 // There are 2.5 different concepts of a 'border' here, which results
     48 // in rather a lot of magic constants. In each case, there are 2
     49 // numbers, one for medium res and one for high-res. All sizes are in pixels.
     50 
     51 // Firstly, we have the extra padding that webkit needs to know about,
     52 // which defines how much bigger this element is made by the
     53 // asset. This is actually a bit broader than the actual border on the
     54 // asset, to make things look less cramped. The border is the same
     55 // width on all sides, except on the right when it's significantly
     56 // wider to allow for the arrow.
     57 const int RenderSkinCombo::arrowMargin[2] = {22, 34};
     58 const int RenderSkinCombo::padMargin[2] = {2, 5};
     59 
     60 // Then we have the borders used for the 9-patch stretch. The
     61 // rectangle at the centre of these borders is entirely below and to
     62 // the left of the arrow in the asset. Hence the border widths are the
     63 // same for the bottom and left, but are different for the top. The
     64 // right hand border width happens to be the same as arrowMargin
     65 // defined above.
     66 static const int        stretchMargin[2] = {3, 5};   // border width for the bottom and left of the 9-patch
     67 static const int        stretchTop[2] = {15, 23};     // border width for the top of the 9-patch
     68 
     69 // Finally, if the border is defined by the CSS, we only draw the
     70 // arrow and not the border. We do this by drawing the relevant subset
     71 // of the bitmap, which must now be precisely determined by what's in
     72 // the asset with no extra padding to make things look properly
     73 // spaced. The border to remove at the top, right and bottom of the
     74 // image is the same as stretchMargin above, but we need to know the width
     75 // of the arrow.
     76 static const int arrowWidth[2] = {22, 31};
     77 
     78 RenderSkinCombo::Resolution RenderSkinCombo::resolution = MedRes;
     79 
     80 const SkIRect RenderSkinCombo::margin[2][2] = {{{ stretchMargin[MedRes], stretchTop[MedRes],
     81                                           RenderSkinCombo::arrowMargin[MedRes] + stretchMargin[MedRes], stretchMargin[MedRes] },
     82                                         {0, stretchTop[MedRes], 0, stretchMargin[MedRes]}},
     83                                        {{ stretchMargin[HighRes], stretchTop[HighRes],
     84                                           RenderSkinCombo::arrowMargin[HighRes] + stretchMargin[HighRes], stretchMargin[HighRes] },
     85                                         {0, stretchTop[HighRes], 0, stretchMargin[HighRes]}}};
     86 static SkBitmap         bitmaps[2][2]; // Collection of assets for a combo box
     87 static bool             isDecoded;      // True if all assets were decoded
     88 
     89 void RenderSkinCombo::Init(android::AssetManager* am, String drawableDirectory)
     90 {
     91     if (isDecoded)
     92         return;
     93 
     94     if (drawableDirectory[drawableDirectory.length() - 5] == 'h')
     95         resolution = HighRes;
     96 
     97     isDecoded = RenderSkinAndroid::DecodeBitmap(am, (drawableDirectory + "combobox_nohighlight.png").utf8().data(), &bitmaps[kNormal][FullAsset]);
     98     isDecoded &= RenderSkinAndroid::DecodeBitmap(am, (drawableDirectory + "combobox_disabled.png").utf8().data(), &bitmaps[kDisabled][FullAsset]);
     99 
    100     int width = bitmaps[kNormal][FullAsset].width();
    101     int height = bitmaps[kNormal][FullAsset].height();
    102     SkIRect  subset;
    103     subset.set(width - arrowWidth[resolution], 0, width, height);
    104     bitmaps[kNormal][FullAsset].extractSubset(&bitmaps[kNormal][NoBorder], subset);
    105     bitmaps[kDisabled][FullAsset].extractSubset(&bitmaps[kDisabled][NoBorder], subset);
    106 }
    107 
    108 
    109 bool RenderSkinCombo::Draw(SkCanvas* canvas, Node* element, int x, int y, int width, int height)
    110 {
    111     if (!isDecoded)
    112         return true;
    113 
    114     State state = (element->isElementNode() && static_cast<Element*>(element)->isEnabledFormControl()) ? kNormal : kDisabled;
    115     height = std::max(height, (stretchMargin[resolution]<<1) + 1);
    116 
    117     SkRect bounds;
    118     BorderStyle drawBorder = FullAsset;
    119 
    120     bounds.set(SkIntToScalar(x+1), SkIntToScalar(y+1), SkIntToScalar(x + width-1), SkIntToScalar(y + height-1));
    121     RenderStyle* style = element->renderStyle();
    122     SkPaint paint;
    123     paint.setColor(style->backgroundColor().rgb());
    124     canvas->drawRect(bounds, paint);
    125 
    126     bounds.set(SkIntToScalar(x), SkIntToScalar(y), SkIntToScalar(x + width), SkIntToScalar(y + height));
    127 
    128     if (style->borderLeftColor().isValid() ||
    129         style->borderRightColor().isValid() ||
    130         style->borderTopColor().isValid() ||
    131         style->borderBottomColor().isValid()) {
    132         bounds.fLeft += SkIntToScalar(width - RenderSkinCombo::extraWidth());
    133         bounds.fRight -= SkIntToScalar(style->borderRightWidth());
    134         bounds.fTop += SkIntToScalar(style->borderTopWidth());
    135         bounds.fBottom -= SkIntToScalar(style->borderBottomWidth());
    136         drawBorder = NoBorder;
    137     }
    138     SkNinePatch::DrawNine(canvas, bounds, bitmaps[state][drawBorder], margin[resolution][drawBorder]);
    139     return false;
    140 }
    141 
    142 }   //WebCore
    143