| /* |
| * Copyright 2006, The Android Open Source Project |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "RenderSkinCombo.h" |
| |
| #include "Document.h" |
| #include "Element.h" |
| #include "Node.h" |
| #include "NodeRenderStyle.h" |
| #include "RenderStyle.h" |
| #include "SkCanvas.h" |
| #include "SkNinePatch.h" |
| #include <wtf/text/CString.h> |
| |
| namespace WebCore { |
| |
| // Indicates if the entire asset is being drawn, or if the border is being |
| // excluded and just the arrow drawn. |
| enum BorderStyle { |
| FullAsset, |
| NoBorder |
| }; |
| |
| // There are 2.5 different concepts of a 'border' here, which results |
| // in rather a lot of magic constants. In each case, there are 2 |
| // numbers, one for medium res and one for high-res. All sizes are in pixels. |
| |
| // Firstly, we have the extra padding that webkit needs to know about, |
| // which defines how much bigger this element is made by the |
| // asset. This is actually a bit broader than the actual border on the |
| // asset, to make things look less cramped. The border is the same |
| // width on all sides, except on the right when it's significantly |
| // wider to allow for the arrow. |
| const int RenderSkinCombo::arrowMargin[2] = {22, 34}; |
| const int RenderSkinCombo::padMargin[2] = {2, 5}; |
| |
| // Then we have the borders used for the 9-patch stretch. The |
| // rectangle at the centre of these borders is entirely below and to |
| // the left of the arrow in the asset. Hence the border widths are the |
| // same for the bottom and left, but are different for the top. The |
| // right hand border width happens to be the same as arrowMargin |
| // defined above. |
| static const int stretchMargin[2] = {3, 5}; // border width for the bottom and left of the 9-patch |
| static const int stretchTop[2] = {15, 23}; // border width for the top of the 9-patch |
| |
| // Finally, if the border is defined by the CSS, we only draw the |
| // arrow and not the border. We do this by drawing the relevant subset |
| // of the bitmap, which must now be precisely determined by what's in |
| // the asset with no extra padding to make things look properly |
| // spaced. The border to remove at the top, right and bottom of the |
| // image is the same as stretchMargin above, but we need to know the width |
| // of the arrow. |
| static const int arrowWidth[2] = {22, 31}; |
| |
| RenderSkinCombo::Resolution RenderSkinCombo::resolution = MedRes; |
| |
| const SkIRect RenderSkinCombo::margin[2][2] = {{{ stretchMargin[MedRes], stretchTop[MedRes], |
| RenderSkinCombo::arrowMargin[MedRes] + stretchMargin[MedRes], stretchMargin[MedRes] }, |
| {0, stretchTop[MedRes], 0, stretchMargin[MedRes]}}, |
| {{ stretchMargin[HighRes], stretchTop[HighRes], |
| RenderSkinCombo::arrowMargin[HighRes] + stretchMargin[HighRes], stretchMargin[HighRes] }, |
| {0, stretchTop[HighRes], 0, stretchMargin[HighRes]}}}; |
| static SkBitmap bitmaps[2][2]; // Collection of assets for a combo box |
| static bool isDecoded; // True if all assets were decoded |
| |
| void RenderSkinCombo::Init(android::AssetManager* am, String drawableDirectory) |
| { |
| if (isDecoded) |
| return; |
| |
| if (drawableDirectory[drawableDirectory.length() - 5] == 'h') |
| resolution = HighRes; |
| |
| isDecoded = RenderSkinAndroid::DecodeBitmap(am, (drawableDirectory + "combobox_nohighlight.png").utf8().data(), &bitmaps[kNormal][FullAsset]); |
| isDecoded &= RenderSkinAndroid::DecodeBitmap(am, (drawableDirectory + "combobox_disabled.png").utf8().data(), &bitmaps[kDisabled][FullAsset]); |
| |
| int width = bitmaps[kNormal][FullAsset].width(); |
| int height = bitmaps[kNormal][FullAsset].height(); |
| SkIRect subset; |
| subset.set(width - arrowWidth[resolution], 0, width, height); |
| bitmaps[kNormal][FullAsset].extractSubset(&bitmaps[kNormal][NoBorder], subset); |
| bitmaps[kDisabled][FullAsset].extractSubset(&bitmaps[kDisabled][NoBorder], subset); |
| } |
| |
| |
| bool RenderSkinCombo::Draw(SkCanvas* canvas, Node* element, int x, int y, int width, int height) |
| { |
| if (!isDecoded) |
| return true; |
| |
| State state = (element->isElementNode() && static_cast<Element*>(element)->isEnabledFormControl()) ? kNormal : kDisabled; |
| height = std::max(height, (stretchMargin[resolution]<<1) + 1); |
| |
| SkRect bounds; |
| BorderStyle drawBorder = FullAsset; |
| |
| bounds.set(SkIntToScalar(x+1), SkIntToScalar(y+1), SkIntToScalar(x + width-1), SkIntToScalar(y + height-1)); |
| RenderStyle* style = element->renderStyle(); |
| SkPaint paint; |
| paint.setColor(style->visitedDependentColor(CSSPropertyBackgroundColor).rgb()); |
| canvas->drawRect(bounds, paint); |
| |
| bounds.set(SkIntToScalar(x), SkIntToScalar(y), SkIntToScalar(x + width), SkIntToScalar(y + height)); |
| |
| // If this is an appearance where RenderTheme::paint returns true |
| // without doing anything, this means that |
| // RenderBox::PaintBoxDecorationWithSize will end up painting the |
| // border, so we shouldn't paint a border here. |
| if (style->appearance() == MenulistButtonPart || |
| style->appearance() == ListboxPart || |
| style->appearance() == TextFieldPart || |
| style->appearance() == TextAreaPart) { |
| bounds.fLeft += SkIntToScalar(width - RenderSkinCombo::extraWidth()); |
| bounds.fRight -= SkIntToScalar(style->borderRightWidth()); |
| bounds.fTop += SkIntToScalar(style->borderTopWidth()); |
| bounds.fBottom -= SkIntToScalar(style->borderBottomWidth()); |
| drawBorder = NoBorder; |
| } |
| SkNinePatch::DrawNine(canvas, bounds, bitmaps[state][drawBorder], margin[resolution][drawBorder]); |
| return false; |
| } |
| |
| } //WebCore |