NinePatchImpl.cpp revision d8f904f256b82e48e9a85561eb96e15399b0b2d9
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** Copyright 2006, The Android Open Source Project 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License"); 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** you may not use this file except in compliance with the License. 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** You may obtain a copy of the License at 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** http://www.apache.org/licenses/LICENSE-2.0 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** Unless required by applicable law or agreed to in writing, software 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** distributed under the License is distributed on an "AS IS" BASIS, 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** See the License for the specific language governing permissions and 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** limitations under the License. 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project*/ 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 184c5efe9290543b723b76a8bd48518da1ae1dcb26Derek Sollenberger#include "utils/NinePatch.h" 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkBitmap.h" 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkCanvas.h" 22ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe#include "SkColorPriv.h" 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkNinePatch.h" 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkPaint.h" 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkUnPreMultiply.h" 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Log.h> 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 294c5efe9290543b723b76a8bd48518da1ae1dcb26Derek Sollenbergernamespace android { 304c5efe9290543b723b76a8bd48518da1ae1dcb26Derek Sollenberger 31ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampestatic const bool kUseTrace = true; 32ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampestatic bool gTrace = false; 33ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic bool getColor(const SkBitmap& bitmap, int x, int y, SkColor* c) { 351103b3255945d2eb2fa9c191e84e2270b343cca9Mike Reed switch (bitmap.colorType()) { 361103b3255945d2eb2fa9c191e84e2270b343cca9Mike Reed case kN32_SkColorType: 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *c = SkUnPreMultiply::PMColorToColor(*bitmap.getAddr32(x, y)); 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 391103b3255945d2eb2fa9c191e84e2270b343cca9Mike Reed case kRGB_565_SkColorType: 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *c = SkPixel16ToPixel32(*bitmap.getAddr16(x, y)); 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 421103b3255945d2eb2fa9c191e84e2270b343cca9Mike Reed case kARGB_4444_SkColorType: 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *c = SkUnPreMultiply::PMColorToColor( 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkPixel4444ToPixel32(*bitmap.getAddr16(x, y))); 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 461103b3255945d2eb2fa9c191e84e2270b343cca9Mike Reed case kIndex_8_SkColorType: { 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkColorTable* ctable = bitmap.getColorTable(); 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *c = SkUnPreMultiply::PMColorToColor( 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (*ctable)[*bitmap.getAddr8(x, y)]); 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic SkColor modAlpha(SkColor c, int alpha) { 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int scale = alpha + (alpha >> 7); 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int a = SkColorGetA(c) * scale >> 8; 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return SkColorSetA(c, a); 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 64d8f904f256b82e48e9a85561eb96e15399b0b2d9Tom Hudsonstatic void drawStretchyPatch(SkCanvas* canvas, SkIRect& src, const SkRect& dst, 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const SkBitmap& bitmap, const SkPaint& paint, 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkColor initColor, uint32_t colorHint, 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bool hasXfer) { 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (colorHint != android::Res_png_9patch::NO_COLOR) { 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ((SkPaint*)&paint)->setColor(modAlpha(colorHint, paint.getAlpha())); 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas->drawRect(dst, paint); 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ((SkPaint*)&paint)->setColor(initColor); 72d8f904f256b82e48e9a85561eb96e15399b0b2d9Tom Hudson } else if (src.width() == 1 && src.height() == 1) { 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkColor c; 74d8f904f256b82e48e9a85561eb96e15399b0b2d9Tom Hudson if (!getColor(bitmap, src.fLeft, src.fTop, &c)) { 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project goto SLOW_CASE; 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (0 != c || hasXfer) { 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkColor prev = paint.getColor(); 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ((SkPaint*)&paint)->setColor(c); 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas->drawRect(dst, paint); 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ((SkPaint*)&paint)->setColor(prev); 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SLOW_CASE: 85d8f904f256b82e48e9a85561eb96e15399b0b2d9Tom Hudson canvas->drawBitmapRect(bitmap, &src, dst, &paint); 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectSkScalar calculateStretch(SkScalar boundsLimit, SkScalar startingPoint, 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int srcSpace, int numStrechyPixelsRemaining, 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numFixedPixelsRemaining) { 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkScalar spaceRemaining = boundsLimit - startingPoint; 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkScalar stretchySpaceRemaining = 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project spaceRemaining - SkIntToScalar(numFixedPixelsRemaining); 9547b3441537b182a61d3a41d39095c40761d49457Mike Reed return srcSpace * stretchySpaceRemaining / numStrechyPixelsRemaining; 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 984c5efe9290543b723b76a8bd48518da1ae1dcb26Derek Sollenbergervoid NinePatch::Draw(SkCanvas* canvas, const SkRect& bounds, 994c5efe9290543b723b76a8bd48518da1ae1dcb26Derek Sollenberger const SkBitmap& bitmap, const Res_png_9patch& chunk, 1004c5efe9290543b723b76a8bd48518da1ae1dcb26Derek Sollenberger const SkPaint* paint, SkRegion** outRegion) { 101ca79cf69d09efa0c327e9b1237d86a119aea5da7Derek Sollenberger if (canvas && canvas->quickReject(bounds)) { 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 104211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed 105211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed SkPaint defaultPaint; 106211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed if (NULL == paint) { 107211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed // matches default dither in NinePatchDrawable.java. 108211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed defaultPaint.setDither(true); 109211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed paint = &defaultPaint; 110211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed } 1116381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath 1126381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath const int32_t* xDivs = chunk.getXDivs(); 1136381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath const int32_t* yDivs = chunk.getYDivs(); 114d39d1affe82cb8c21d32baaa5fbb2d6afb806f8eDerek Sollenberger // if our SkCanvas were back by GL we should enable this and draw this as 115d39d1affe82cb8c21d32baaa5fbb2d6afb806f8eDerek Sollenberger // a mesh, which will be faster in most cases. 11646d8444631b4b1253a76bfcc78a29d26014d022fDan Albert if ((false)) { 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkNinePatch::DrawMesh(canvas, bounds, bitmap, 1186381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath xDivs, chunk.numXDivs, 1196381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath yDivs, chunk.numYDivs, 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint); 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 124ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe if (kUseTrace) { 125ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gTrace = true; 126ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe } 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkASSERT(canvas || outRegion); 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 130ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe if (kUseTrace) { 131ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe if (canvas) { 132ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe const SkMatrix& m = canvas->getTotalMatrix(); 133ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe ALOGV("ninepatch [%g %g %g] [%g %g %g]\n", 134ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe SkScalarToFloat(m[0]), SkScalarToFloat(m[1]), SkScalarToFloat(m[2]), 135ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe SkScalarToFloat(m[3]), SkScalarToFloat(m[4]), SkScalarToFloat(m[5])); 136ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe } 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 138ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe ALOGV("======== ninepatch bounds [%g %g]\n", SkScalarToFloat(bounds.width()), 139ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe SkScalarToFloat(bounds.height())); 14071f2cf116aab893e224056c38ab146bd1538dd3eSteve Block ALOGV("======== ninepatch paint bm [%d,%d]\n", bitmap.width(), bitmap.height()); 1416381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath ALOGV("======== ninepatch xDivs [%d,%d]\n", xDivs[0], xDivs[1]); 1426381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath ALOGV("======== ninepatch yDivs [%d,%d]\n", yDivs[0], yDivs[1]); 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (bounds.isEmpty() || 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bitmap.width() == 0 || bitmap.height() == 0 || 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (paint && paint->getXfermode() == NULL && paint->getAlpha() == 0)) 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 149ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe if (kUseTrace) { 150ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe ALOGV("======== abort ninepatch draw\n"); 151ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe } 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // should try a quick-reject test before calling lockPixels 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkAutoLockPixels alp(bitmap); 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // after the lock, it is valid to check getPixels() 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (bitmap.getPixels() == NULL) 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const bool hasXfer = paint->getXfermode() != NULL; 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkRect dst; 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkIRect src; 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1666381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath const int32_t x0 = xDivs[0]; 1676381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath const int32_t y0 = yDivs[0]; 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const SkColor initColor = ((SkPaint*)paint)->getColor(); 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const uint8_t numXDivs = chunk.numXDivs; 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const uint8_t numYDivs = chunk.numYDivs; 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int i; 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int j; 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int colorIndex = 0; 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project uint32_t color; 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bool xIsStretchable; 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const bool initialXIsStretchable = (x0 == 0); 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bool yIsStretchable = (y0 == 0); 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const int bitmapWidth = bitmap.width(); 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const int bitmapHeight = bitmap.height(); 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 181462dd010467fdf1ab0cb49e021a92d14f2163c8cLeon Scroggins III // Number of bytes needed for dstRights array. 182462dd010467fdf1ab0cb49e021a92d14f2163c8cLeon Scroggins III // Need to cast numXDivs to a larger type to avoid overflow. 183462dd010467fdf1ab0cb49e021a92d14f2163c8cLeon Scroggins III const size_t dstBytes = ((size_t) numXDivs + 1) * sizeof(SkScalar); 184462dd010467fdf1ab0cb49e021a92d14f2163c8cLeon Scroggins III SkScalar* dstRights = (SkScalar*) alloca(dstBytes); 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bool dstRightsHaveBeenCached = false; 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numStretchyXPixelsRemaining = 0; 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (i = 0; i < numXDivs; i += 2) { 1896381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath numStretchyXPixelsRemaining += xDivs[i + 1] - xDivs[i]; 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numFixedXPixelsRemaining = bitmapWidth - numStretchyXPixelsRemaining; 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numStretchyYPixelsRemaining = 0; 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (i = 0; i < numYDivs; i += 2) { 1946381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath numStretchyYPixelsRemaining += yDivs[i + 1] - yDivs[i]; 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numFixedYPixelsRemaining = bitmapHeight - numStretchyYPixelsRemaining; 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 198ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe if (kUseTrace) { 199ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe ALOGV("NinePatch [%d %d] bounds [%g %g %g %g] divs [%d %d]\n", 200ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe bitmap.width(), bitmap.height(), 201ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop), 202ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe SkScalarToFloat(bounds.width()), SkScalarToFloat(bounds.height()), 203ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe numXDivs, numYDivs); 204ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe } 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project src.fTop = 0; 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.fTop = bounds.fTop; 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The first row always starts with the top being at y=0 and the bottom 2098b5f80ef9f4c98bf18f97e28c7747acb896a365eRoger Hu // being either yDivs[1] (if yDivs[0]=0) or yDivs[0]. In the former case 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the first row is stretchable along the Y axis, otherwise it is fixed. 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The last row always ends with the bottom being bitmap.height and the top 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // being either yDivs[numYDivs-2] (if yDivs[numYDivs-1]=bitmap.height) or 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // yDivs[numYDivs-1]. In the former case the last row is stretchable along 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the Y axis, otherwise it is fixed. 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The first and last columns are similarly treated with respect to the X 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // axis. 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The above is to help explain some of the special casing that goes on the 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // code below. 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The initial yDiv and whether the first row is considered stretchable or 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // not depends on whether yDiv[0] was zero or not. 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (j = yIsStretchable ? 1 : 0; 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project j <= numYDivs && src.fTop < bitmapHeight; 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project j++, yIsStretchable = !yIsStretchable) { 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project src.fLeft = 0; 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.fLeft = bounds.fLeft; 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (j == numYDivs) { 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project src.fBottom = bitmapHeight; 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.fBottom = bounds.fBottom; 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2336381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath src.fBottom = yDivs[j]; 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const int srcYSize = src.fBottom - src.fTop; 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (yIsStretchable) { 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.fBottom = dst.fTop + calculateStretch(bounds.fBottom, dst.fTop, 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project srcYSize, 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numStretchyYPixelsRemaining, 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numFixedYPixelsRemaining); 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numStretchyYPixelsRemaining -= srcYSize; 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.fBottom = dst.fTop + SkIntToScalar(srcYSize); 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numFixedYPixelsRemaining -= srcYSize; 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project xIsStretchable = initialXIsStretchable; 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The initial xDiv and whether the first column is considered 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // stretchable or not depends on whether xDiv[0] was zero or not. 2506381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath const uint32_t* colors = chunk.getColors(); 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (i = xIsStretchable ? 1 : 0; 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i <= numXDivs && src.fLeft < bitmapWidth; 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++, xIsStretchable = !xIsStretchable) { 2546381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath color = colors[colorIndex++]; 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (i == numXDivs) { 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project src.fRight = bitmapWidth; 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.fRight = bounds.fRight; 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2596381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath src.fRight = xDivs[i]; 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dstRightsHaveBeenCached) { 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.fRight = dstRights[i]; 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const int srcXSize = src.fRight - src.fLeft; 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (xIsStretchable) { 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.fRight = dst.fLeft + calculateStretch(bounds.fRight, dst.fLeft, 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project srcXSize, 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numStretchyXPixelsRemaining, 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numFixedXPixelsRemaining); 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numStretchyXPixelsRemaining -= srcXSize; 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.fRight = dst.fLeft + SkIntToScalar(srcXSize); 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numFixedXPixelsRemaining -= srcXSize; 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dstRights[i] = dst.fRight; 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If this horizontal patch is too small to be displayed, leave 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the destination left edge where it is and go on to the next patch 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // in the source. 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (src.fLeft >= src.fRight) { 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project src.fLeft = src.fRight; 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Make sure that we actually have room to draw any bits 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dst.fRight <= dst.fLeft || dst.fBottom <= dst.fTop) { 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project goto nextDiv; 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If this patch is transparent, skip and don't draw. 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (color == android::Res_png_9patch::TRANSPARENT_COLOR && !hasXfer) { 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (outRegion) { 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (*outRegion == NULL) { 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *outRegion = new SkRegion(); 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkIRect idst; 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.round(&idst); 2966215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block //ALOGI("Adding trans rect: (%d,%d)-(%d,%d)\n", 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // idst.fLeft, idst.fTop, idst.fRight, idst.fBottom); 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (*outRegion)->op(idst, SkRegion::kUnion_Op); 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project goto nextDiv; 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (canvas) { 303ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe if (kUseTrace) { 304ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe ALOGV("-- src [%d %d %d %d] dst [%g %g %g %g]\n", 305ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe src.fLeft, src.fTop, src.width(), src.height(), 306ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe SkScalarToFloat(dst.fLeft), SkScalarToFloat(dst.fTop), 307ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe SkScalarToFloat(dst.width()), SkScalarToFloat(dst.height())); 308ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe if (2 == src.width() && SkIntToScalar(5) == dst.width()) { 309ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe ALOGV("--- skip patch\n"); 310ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe } 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project drawStretchyPatch(canvas, src, dst, bitmap, *paint, initColor, 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project color, hasXfer); 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectnextDiv: 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project src.fLeft = src.fRight; 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.fLeft = dst.fRight; 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project src.fTop = src.fBottom; 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.fTop = dst.fBottom; 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dstRightsHaveBeenCached = true; 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 3254c5efe9290543b723b76a8bd48518da1ae1dcb26Derek Sollenberger 3264c5efe9290543b723b76a8bd48518da1ae1dcb26Derek Sollenberger} // namespace android 327