xref: /aosp_15_r20/frameworks/base/libs/hwui/jni/NinePatchPeeker.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker  * Copyright (C) 2011 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker  *
4*d57664e9SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker  *
8*d57664e9SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker  *
10*d57664e9SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker  * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker  */
16*d57664e9SAndroid Build Coastguard Worker 
17*d57664e9SAndroid Build Coastguard Worker #include "NinePatchPeeker.h"
18*d57664e9SAndroid Build Coastguard Worker 
19*d57664e9SAndroid Build Coastguard Worker #include <SkScalar.h>
20*d57664e9SAndroid Build Coastguard Worker #include <cutils/compiler.h>
21*d57664e9SAndroid Build Coastguard Worker 
22*d57664e9SAndroid Build Coastguard Worker using namespace android;
23*d57664e9SAndroid Build Coastguard Worker 
readChunk(const char tag[],const void * data,size_t length)24*d57664e9SAndroid Build Coastguard Worker bool NinePatchPeeker::readChunk(const char tag[], const void* data, size_t length) {
25*d57664e9SAndroid Build Coastguard Worker     if (!strcmp("npTc", tag) && length >= sizeof(Res_png_9patch)) {
26*d57664e9SAndroid Build Coastguard Worker         Res_png_9patch* patch = (Res_png_9patch*) data;
27*d57664e9SAndroid Build Coastguard Worker         size_t patchSize = patch->serializedSize();
28*d57664e9SAndroid Build Coastguard Worker         if (length != patchSize) {
29*d57664e9SAndroid Build Coastguard Worker             return false;
30*d57664e9SAndroid Build Coastguard Worker         }
31*d57664e9SAndroid Build Coastguard Worker         // You have to copy the data because it is owned by the png reader
32*d57664e9SAndroid Build Coastguard Worker         Res_png_9patch* patchNew = (Res_png_9patch*) malloc(patchSize);
33*d57664e9SAndroid Build Coastguard Worker         memcpy(patchNew, patch, patchSize);
34*d57664e9SAndroid Build Coastguard Worker         Res_png_9patch::deserialize(patchNew);
35*d57664e9SAndroid Build Coastguard Worker         patchNew->fileToDevice();
36*d57664e9SAndroid Build Coastguard Worker         free(mPatch);
37*d57664e9SAndroid Build Coastguard Worker         mPatch = patchNew;
38*d57664e9SAndroid Build Coastguard Worker         mPatchSize = patchSize;
39*d57664e9SAndroid Build Coastguard Worker     } else if (!strcmp("npLb", tag) && length == sizeof(int32_t) * 4) {
40*d57664e9SAndroid Build Coastguard Worker         mHasInsets = true;
41*d57664e9SAndroid Build Coastguard Worker         memcpy(&mOpticalInsets, data, sizeof(int32_t) * 4);
42*d57664e9SAndroid Build Coastguard Worker     } else if (!strcmp("npOl", tag) && length == 24) { // 4 int32_ts, 1 float, 1 int32_t sized byte
43*d57664e9SAndroid Build Coastguard Worker         mHasInsets = true;
44*d57664e9SAndroid Build Coastguard Worker         memcpy(&mOutlineInsets, data, sizeof(int32_t) * 4);
45*d57664e9SAndroid Build Coastguard Worker         mOutlineRadius = ((const float*)data)[4];
46*d57664e9SAndroid Build Coastguard Worker         mOutlineAlpha = ((const int32_t*)data)[5] & 0xff;
47*d57664e9SAndroid Build Coastguard Worker     }
48*d57664e9SAndroid Build Coastguard Worker     return true;    // keep on decoding
49*d57664e9SAndroid Build Coastguard Worker }
50*d57664e9SAndroid Build Coastguard Worker 
scaleDivRange(int32_t * divs,int count,float scale,int maxValue)51*d57664e9SAndroid Build Coastguard Worker static void scaleDivRange(int32_t* divs, int count, float scale, int maxValue) {
52*d57664e9SAndroid Build Coastguard Worker     for (int i = 0; i < count; i++) {
53*d57664e9SAndroid Build Coastguard Worker         divs[i] = int32_t(divs[i] * scale + 0.5f);
54*d57664e9SAndroid Build Coastguard Worker         if (i > 0 && divs[i] == divs[i - 1]) {
55*d57664e9SAndroid Build Coastguard Worker             divs[i]++; // avoid collisions
56*d57664e9SAndroid Build Coastguard Worker         }
57*d57664e9SAndroid Build Coastguard Worker     }
58*d57664e9SAndroid Build Coastguard Worker 
59*d57664e9SAndroid Build Coastguard Worker     if (CC_UNLIKELY(divs[count - 1] > maxValue)) {
60*d57664e9SAndroid Build Coastguard Worker         // if the collision avoidance above put some divs outside the bounds of the bitmap,
61*d57664e9SAndroid Build Coastguard Worker         // slide outer stretchable divs inward to stay within bounds
62*d57664e9SAndroid Build Coastguard Worker         int highestAvailable = maxValue;
63*d57664e9SAndroid Build Coastguard Worker         for (int i = count - 1; i >= 0; i--) {
64*d57664e9SAndroid Build Coastguard Worker             divs[i] = highestAvailable;
65*d57664e9SAndroid Build Coastguard Worker             if (i > 0 && divs[i] <= divs[i-1]) {
66*d57664e9SAndroid Build Coastguard Worker                 // keep shifting
67*d57664e9SAndroid Build Coastguard Worker                 highestAvailable = divs[i] - 1;
68*d57664e9SAndroid Build Coastguard Worker             } else {
69*d57664e9SAndroid Build Coastguard Worker                 break;
70*d57664e9SAndroid Build Coastguard Worker             }
71*d57664e9SAndroid Build Coastguard Worker         }
72*d57664e9SAndroid Build Coastguard Worker     }
73*d57664e9SAndroid Build Coastguard Worker }
74*d57664e9SAndroid Build Coastguard Worker 
scale(float scaleX,float scaleY,int scaledWidth,int scaledHeight)75*d57664e9SAndroid Build Coastguard Worker void NinePatchPeeker::scale(float scaleX, float scaleY, int scaledWidth, int scaledHeight) {
76*d57664e9SAndroid Build Coastguard Worker     if (!mPatch) {
77*d57664e9SAndroid Build Coastguard Worker         return;
78*d57664e9SAndroid Build Coastguard Worker     }
79*d57664e9SAndroid Build Coastguard Worker 
80*d57664e9SAndroid Build Coastguard Worker     // The max value for the divRange is one pixel less than the actual max to ensure that the size
81*d57664e9SAndroid Build Coastguard Worker     // of the last div is not zero. A div of size 0 is considered invalid input and will not render.
82*d57664e9SAndroid Build Coastguard Worker     if (!SkScalarNearlyEqual(scaleX, 1.0f)) {
83*d57664e9SAndroid Build Coastguard Worker         mPatch->paddingLeft   = int(mPatch->paddingLeft   * scaleX + 0.5f);
84*d57664e9SAndroid Build Coastguard Worker         mPatch->paddingRight  = int(mPatch->paddingRight  * scaleX + 0.5f);
85*d57664e9SAndroid Build Coastguard Worker         scaleDivRange(mPatch->getXDivs(), mPatch->numXDivs, scaleX, scaledWidth - 1);
86*d57664e9SAndroid Build Coastguard Worker     }
87*d57664e9SAndroid Build Coastguard Worker 
88*d57664e9SAndroid Build Coastguard Worker     if (!SkScalarNearlyEqual(scaleY, 1.0f)) {
89*d57664e9SAndroid Build Coastguard Worker         mPatch->paddingTop    = int(mPatch->paddingTop    * scaleY + 0.5f);
90*d57664e9SAndroid Build Coastguard Worker         mPatch->paddingBottom = int(mPatch->paddingBottom * scaleY + 0.5f);
91*d57664e9SAndroid Build Coastguard Worker         scaleDivRange(mPatch->getYDivs(), mPatch->numYDivs, scaleY, scaledHeight - 1);
92*d57664e9SAndroid Build Coastguard Worker     }
93*d57664e9SAndroid Build Coastguard Worker }
94