1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.ui.resources.statics; 6 7 import android.graphics.Bitmap; 8 import android.graphics.NinePatch; 9 import android.graphics.Rect; 10 11 import java.nio.BufferUnderflowException; 12 import java.nio.ByteBuffer; 13 import java.nio.ByteOrder; 14 15 /** 16 * A helper class to decode and expose relevant 9-patch data from a Bitmap. 17 */ 18 public class NinePatchData { 19 private final int mWidth; 20 private final int mHeight; 21 private final Rect mPadding; 22 private final int[] mDivX; 23 private final int[] mDivY; 24 25 private Rect mAperture; 26 27 /** 28 * Creates a {@link NinePatchData} that stores 9-patch metadata. 29 * @param width The width of the underlying bitmap. 30 * @param height The height of the underlying bitmap. 31 * @param padding The padding of the 9-patch for the content area. This padding is a set of 32 * insets (left = left padding, top = top padding, right = right padding, 33 * bottom = bottom padding). 34 * @param divX A run-length encoded list of stretch regions along the x dimension. The 35 * regions will go from 0 -> divX[0] - 1, divX[0] -> divX[1] - 1, etc.. 36 * @param divY A run-length encoded list of stretch regions along the y dimension. The 37 * regions will go from 0 -> divY[0] - 1, divY[0] -> divY[1] - 1, etc.. 38 */ NinePatchData(int width, int height, Rect padding, int[] divX, int[] divY)39 private NinePatchData(int width, int height, Rect padding, int[] divX, int[] divY) { 40 mWidth = width; 41 mHeight = height; 42 mPadding = new Rect( 43 padding.left, padding.top, mWidth - padding.right, mHeight - padding.bottom); 44 45 mDivX = new int[divX.length]; 46 mDivY = new int[divY.length]; 47 48 System.arraycopy(divX, 0, mDivX, 0, divX.length); 49 System.arraycopy(divY, 0, mDivY, 0, divY.length); 50 51 mAperture = new Rect(mDivX[0], mDivY[0], mDivX[1], mDivY[1]); 52 } 53 54 /** 55 * @return The padded content area of this 9-patch. 56 */ getPadding()57 public Rect getPadding() { 58 return mPadding; 59 } 60 61 /** 62 * This class only exposes one 9-patch stretch region. 63 * @return The aperture of this 9-patch. This specifies the center of the 9-patch, with the 64 * surrounding areas being stretchable. 65 */ getAperture()66 public Rect getAperture() { 67 return mAperture; 68 } 69 70 /** 71 * Attempts to decode 9-patch data from a {@link Bitmap}. 72 * @param bitmap The {@link Bitmap} to check. 73 * @return An instance of {@link NinePatchData} representing the 9-patch information 74 * encoded in {@code bitmap} or {@code null} if the {@link Bitmap} wasn't a 75 * 9-patch. 76 */ create(Bitmap bitmap)77 public static NinePatchData create(Bitmap bitmap) { 78 if (bitmap == null) return null; 79 80 try { 81 byte[] chunk = bitmap.getNinePatchChunk(); 82 if (chunk == null || !NinePatch.isNinePatchChunk(chunk)) return null; 83 84 ByteBuffer buffer = ByteBuffer.wrap(chunk).order(ByteOrder.nativeOrder()); 85 86 // int8_t wasDeserialized 87 if (buffer.get() == 0) return null; 88 89 // int8_t numXDivs 90 int numDivX = buffer.get(); 91 if (numDivX == 0 || (numDivX & 0x01) != 0) return null; 92 93 // int8_t numYDivs 94 int numDivY = buffer.get(); 95 if (numDivY == 0 || (numDivY & 0x01) != 0) return null; 96 97 // int8_t numColors 98 buffer.get(); 99 100 // uint32_t xDivsOffset 101 buffer.getInt(); 102 103 // uint32_t yDivsOffset 104 buffer.getInt(); 105 106 Rect padding = new Rect(); 107 108 // uint32_t paddingLeft 109 padding.left = buffer.getInt(); 110 111 // uint32_t paddingRight 112 padding.right = buffer.getInt(); 113 114 // uint32_t paddingTop 115 padding.top = buffer.getInt(); 116 117 // uint32_t paddingBottom 118 padding.bottom = buffer.getInt(); 119 120 // uint32_t colorsOffset 121 buffer.getInt(); 122 123 // uint32_t uint32_t uint32_t ... 124 int[] divX = new int[numDivX]; 125 for (int i = 0; i < numDivX; i++) divX[i] = buffer.getInt(); 126 127 // uint32_t uint32_t uint32_t ... 128 int[] divY = new int[numDivY]; 129 for (int i = 0; i < numDivY; i++) divY[i] = buffer.getInt(); 130 131 return new NinePatchData(bitmap.getWidth(), bitmap.getHeight(), padding, divX, divY); 132 } catch (BufferUnderflowException ex) { 133 return null; 134 } 135 } 136 }