NinePatchImpl.cpp revision 46d8444631b4b1253a76bfcc78a29d26014d022f
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 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "NinePatch" 198cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn#define LOG_NDEBUG 1 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21b13b9bdad2baf6ad1ec2e56b6b7598fa20f55fc4Mathias Agopian#include <androidfw/ResourceTypes.h> 228cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn#include <utils/Log.h> 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkBitmap.h" 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkCanvas.h" 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkNinePatch.h" 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkPaint.h" 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkUnPreMultiply.h" 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 308cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn#define USE_TRACE 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#ifdef USE_TRACE 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static bool gTrace; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkColorPriv.h" 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Log.h> 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic bool getColor(const SkBitmap& bitmap, int x, int y, SkColor* c) { 411103b3255945d2eb2fa9c191e84e2270b343cca9Mike Reed switch (bitmap.colorType()) { 421103b3255945d2eb2fa9c191e84e2270b343cca9Mike Reed case kN32_SkColorType: 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *c = SkUnPreMultiply::PMColorToColor(*bitmap.getAddr32(x, y)); 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 451103b3255945d2eb2fa9c191e84e2270b343cca9Mike Reed case kRGB_565_SkColorType: 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *c = SkPixel16ToPixel32(*bitmap.getAddr16(x, y)); 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 481103b3255945d2eb2fa9c191e84e2270b343cca9Mike Reed case kARGB_4444_SkColorType: 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *c = SkUnPreMultiply::PMColorToColor( 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkPixel4444ToPixel32(*bitmap.getAddr16(x, y))); 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 521103b3255945d2eb2fa9c191e84e2270b343cca9Mike Reed case kIndex_8_SkColorType: { 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkColorTable* ctable = bitmap.getColorTable(); 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *c = SkUnPreMultiply::PMColorToColor( 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (*ctable)[*bitmap.getAddr8(x, y)]); 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic SkColor modAlpha(SkColor c, int alpha) { 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int scale = alpha + (alpha >> 7); 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int a = SkColorGetA(c) * scale >> 8; 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return SkColorSetA(c, a); 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void drawStretchyPatch(SkCanvas* canvas, SkIRect& src, const SkRect& dst, 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const SkBitmap& bitmap, const SkPaint& paint, 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkColor initColor, uint32_t colorHint, 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bool hasXfer) { 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (colorHint != android::Res_png_9patch::NO_COLOR) { 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ((SkPaint*)&paint)->setColor(modAlpha(colorHint, paint.getAlpha())); 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas->drawRect(dst, paint); 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ((SkPaint*)&paint)->setColor(initColor); 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (src.width() == 1 && src.height() == 1) { 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkColor c; 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!getColor(bitmap, src.fLeft, src.fTop, &c)) { 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project goto SLOW_CASE; 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (0 != c || hasXfer) { 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkColor prev = paint.getColor(); 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ((SkPaint*)&paint)->setColor(c); 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas->drawRect(dst, paint); 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ((SkPaint*)&paint)->setColor(prev); 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SLOW_CASE: 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project canvas->drawBitmapRect(bitmap, &src, dst, &paint); 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectSkScalar calculateStretch(SkScalar boundsLimit, SkScalar startingPoint, 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int srcSpace, int numStrechyPixelsRemaining, 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numFixedPixelsRemaining) { 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkScalar spaceRemaining = boundsLimit - startingPoint; 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkScalar stretchySpaceRemaining = 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project spaceRemaining - SkIntToScalar(numFixedPixelsRemaining); 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return SkScalarMulDiv(srcSpace, stretchySpaceRemaining, 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numStrechyPixelsRemaining); 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds, 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const SkBitmap& bitmap, const android::Res_png_9patch& chunk, 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const SkPaint* paint, SkRegion** outRegion) { 108ca79cf69d09efa0c327e9b1237d86a119aea5da7Derek Sollenberger if (canvas && canvas->quickReject(bounds)) { 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 111211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed 112211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed SkPaint defaultPaint; 113211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed if (NULL == paint) { 114211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed // matches default dither in NinePatchDrawable.java. 115211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed defaultPaint.setDither(true); 116211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed paint = &defaultPaint; 117211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed } 1186381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath 1196381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath const int32_t* xDivs = chunk.getXDivs(); 1206381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath const int32_t* yDivs = chunk.getYDivs(); 121d39d1affe82cb8c21d32baaa5fbb2d6afb806f8eDerek Sollenberger // if our SkCanvas were back by GL we should enable this and draw this as 122d39d1affe82cb8c21d32baaa5fbb2d6afb806f8eDerek Sollenberger // a mesh, which will be faster in most cases. 12346d8444631b4b1253a76bfcc78a29d26014d022fDan Albert if ((false)) { 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkNinePatch::DrawMesh(canvas, bounds, bitmap, 1256381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath xDivs, chunk.numXDivs, 1266381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath yDivs, chunk.numYDivs, 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint); 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#ifdef USE_TRACE 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project gTrace = true; 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkASSERT(canvas || outRegion); 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1378cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn#ifdef USE_TRACE 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (canvas) { 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const SkMatrix& m = canvas->getTotalMatrix(); 14071f2cf116aab893e224056c38ab146bd1538dd3eSteve Block ALOGV("ninepatch [%g %g %g] [%g %g %g]\n", 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkScalarToFloat(m[0]), SkScalarToFloat(m[1]), SkScalarToFloat(m[2]), 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkScalarToFloat(m[3]), SkScalarToFloat(m[4]), SkScalarToFloat(m[5])); 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#ifdef USE_TRACE 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (gTrace) { 14871f2cf116aab893e224056c38ab146bd1538dd3eSteve Block ALOGV("======== ninepatch bounds [%g %g]\n", SkScalarToFloat(bounds.width()), SkScalarToFloat(bounds.height())); 14971f2cf116aab893e224056c38ab146bd1538dd3eSteve Block ALOGV("======== ninepatch paint bm [%d,%d]\n", bitmap.width(), bitmap.height()); 1506381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath ALOGV("======== ninepatch xDivs [%d,%d]\n", xDivs[0], xDivs[1]); 1516381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath ALOGV("======== ninepatch yDivs [%d,%d]\n", yDivs[0], yDivs[1]); 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (bounds.isEmpty() || 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bitmap.width() == 0 || bitmap.height() == 0 || 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (paint && paint->getXfermode() == NULL && paint->getAlpha() == 0)) 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#ifdef USE_TRACE 16071f2cf116aab893e224056c38ab146bd1538dd3eSteve Block if (gTrace) ALOGV("======== abort ninepatch draw\n"); 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // should try a quick-reject test before calling lockPixels 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkAutoLockPixels alp(bitmap); 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // after the lock, it is valid to check getPixels() 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (bitmap.getPixels() == NULL) 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const bool hasXfer = paint->getXfermode() != NULL; 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkRect dst; 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkIRect src; 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1766381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath const int32_t x0 = xDivs[0]; 1776381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath const int32_t y0 = yDivs[0]; 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const SkColor initColor = ((SkPaint*)paint)->getColor(); 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const uint8_t numXDivs = chunk.numXDivs; 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const uint8_t numYDivs = chunk.numYDivs; 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int i; 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int j; 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int colorIndex = 0; 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project uint32_t color; 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bool xIsStretchable; 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const bool initialXIsStretchable = (x0 == 0); 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bool yIsStretchable = (y0 == 0); 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const int bitmapWidth = bitmap.width(); 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const int bitmapHeight = bitmap.height(); 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkScalar* dstRights = (SkScalar*) alloca((numXDivs + 1) * sizeof(SkScalar)); 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bool dstRightsHaveBeenCached = false; 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numStretchyXPixelsRemaining = 0; 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (i = 0; i < numXDivs; i += 2) { 1966381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath numStretchyXPixelsRemaining += xDivs[i + 1] - xDivs[i]; 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numFixedXPixelsRemaining = bitmapWidth - numStretchyXPixelsRemaining; 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numStretchyYPixelsRemaining = 0; 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (i = 0; i < numYDivs; i += 2) { 2016381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath numStretchyYPixelsRemaining += yDivs[i + 1] - yDivs[i]; 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numFixedYPixelsRemaining = bitmapHeight - numStretchyYPixelsRemaining; 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2058cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn#ifdef USE_TRACE 20671f2cf116aab893e224056c38ab146bd1538dd3eSteve Block ALOGV("NinePatch [%d %d] bounds [%g %g %g %g] divs [%d %d]\n", 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bitmap.width(), bitmap.height(), 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop), 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkScalarToFloat(bounds.width()), SkScalarToFloat(bounds.height()), 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numXDivs, numYDivs); 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project src.fTop = 0; 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.fTop = bounds.fTop; 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The first row always starts with the top being at y=0 and the bottom 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // being either yDivs[1] (if yDivs[0]=0) of yDivs[0]. In the former case 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the first row is stretchable along the Y axis, otherwise it is fixed. 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The last row always ends with the bottom being bitmap.height and the top 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // being either yDivs[numYDivs-2] (if yDivs[numYDivs-1]=bitmap.height) or 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // yDivs[numYDivs-1]. In the former case the last row is stretchable along 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the Y axis, otherwise it is fixed. 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The first and last columns are similarly treated with respect to the X 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // axis. 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The above is to help explain some of the special casing that goes on the 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // code below. 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The initial yDiv and whether the first row is considered stretchable or 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // not depends on whether yDiv[0] was zero or not. 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (j = yIsStretchable ? 1 : 0; 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project j <= numYDivs && src.fTop < bitmapHeight; 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project j++, yIsStretchable = !yIsStretchable) { 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project src.fLeft = 0; 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.fLeft = bounds.fLeft; 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (j == numYDivs) { 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project src.fBottom = bitmapHeight; 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.fBottom = bounds.fBottom; 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2406381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath src.fBottom = yDivs[j]; 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const int srcYSize = src.fBottom - src.fTop; 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (yIsStretchable) { 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.fBottom = dst.fTop + calculateStretch(bounds.fBottom, dst.fTop, 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project srcYSize, 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numStretchyYPixelsRemaining, 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numFixedYPixelsRemaining); 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numStretchyYPixelsRemaining -= srcYSize; 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.fBottom = dst.fTop + SkIntToScalar(srcYSize); 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numFixedYPixelsRemaining -= srcYSize; 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project xIsStretchable = initialXIsStretchable; 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The initial xDiv and whether the first column is considered 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // stretchable or not depends on whether xDiv[0] was zero or not. 2576381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath const uint32_t* colors = chunk.getColors(); 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (i = xIsStretchable ? 1 : 0; 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i <= numXDivs && src.fLeft < bitmapWidth; 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++, xIsStretchable = !xIsStretchable) { 2616381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath color = colors[colorIndex++]; 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (i == numXDivs) { 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project src.fRight = bitmapWidth; 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.fRight = bounds.fRight; 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2666381dd4ff212a95be30d2b445d40ff419ab076b4Narayan Kamath src.fRight = xDivs[i]; 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dstRightsHaveBeenCached) { 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.fRight = dstRights[i]; 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const int srcXSize = src.fRight - src.fLeft; 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (xIsStretchable) { 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.fRight = dst.fLeft + calculateStretch(bounds.fRight, dst.fLeft, 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project srcXSize, 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numStretchyXPixelsRemaining, 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numFixedXPixelsRemaining); 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numStretchyXPixelsRemaining -= srcXSize; 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.fRight = dst.fLeft + SkIntToScalar(srcXSize); 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numFixedXPixelsRemaining -= srcXSize; 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dstRights[i] = dst.fRight; 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If this horizontal patch is too small to be displayed, leave 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the destination left edge where it is and go on to the next patch 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // in the source. 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (src.fLeft >= src.fRight) { 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project src.fLeft = src.fRight; 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Make sure that we actually have room to draw any bits 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dst.fRight <= dst.fLeft || dst.fBottom <= dst.fTop) { 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project goto nextDiv; 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If this patch is transparent, skip and don't draw. 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (color == android::Res_png_9patch::TRANSPARENT_COLOR && !hasXfer) { 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (outRegion) { 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (*outRegion == NULL) { 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *outRegion = new SkRegion(); 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkIRect idst; 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.round(&idst); 3036215d3ff4b5dfa52a5d8b9a42e343051f31066a5Steve Block //ALOGI("Adding trans rect: (%d,%d)-(%d,%d)\n", 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // idst.fLeft, idst.fTop, idst.fRight, idst.fBottom); 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (*outRegion)->op(idst, SkRegion::kUnion_Op); 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project goto nextDiv; 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (canvas) { 3108cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn#ifdef USE_TRACE 31171f2cf116aab893e224056c38ab146bd1538dd3eSteve Block ALOGV("-- src [%d %d %d %d] dst [%g %g %g %g]\n", 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project src.fLeft, src.fTop, src.width(), src.height(), 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkScalarToFloat(dst.fLeft), SkScalarToFloat(dst.fTop), 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkScalarToFloat(dst.width()), SkScalarToFloat(dst.height())); 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (2 == src.width() && SkIntToScalar(5) == dst.width()) { 31671f2cf116aab893e224056c38ab146bd1538dd3eSteve Block ALOGV("--- skip patch\n"); 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project drawStretchyPatch(canvas, src, dst, bitmap, *paint, initColor, 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project color, hasXfer); 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectnextDiv: 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project src.fLeft = src.fRight; 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.fLeft = dst.fRight; 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project src.fTop = src.fBottom; 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dst.fTop = dst.fBottom; 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dstRightsHaveBeenCached = true; 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 332