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