• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "config.h"
18 
19 #include "NinePatchPeeker.h"
20 #include "RenderSkinNinePatch.h"
21 #include "SkCanvas.h"
22 #include "SkImageDecoder.h"
23 #include "SkNinePatch.h"
24 #include "SkRect.h"
25 #include "SkStream.h"
26 #include "SkTemplates.h"
27 #include <androidfw/Asset.h>
28 #include <androidfw/AssetManager.h>
29 #include <androidfw/ResourceTypes.h>
30 #include <utils/Log.h>
31 
32 class SkPaint;
33 class SkRegion;
34 
35 using namespace android;
36 
37 extern void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds,
38         const SkBitmap& bitmap, const Res_png_9patch& chunk,
39         const SkPaint* paint, SkRegion** outRegion);
40 
decodeAsset(AssetManager * am,const char * filename,NinePatch * ninepatch)41 bool RenderSkinNinePatch::decodeAsset(AssetManager* am, const char* filename, NinePatch* ninepatch) {
42     Asset* asset = am->open(filename, android::Asset::ACCESS_BUFFER);
43     if (!asset) {
44         asset = am->openNonAsset(filename, android::Asset::ACCESS_BUFFER);
45         if (!asset) {
46             return false;
47         }
48     }
49 
50     SkImageDecoder::Mode mode = SkImageDecoder::kDecodePixels_Mode;
51     SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
52     SkMemoryStream stream(asset->getBuffer(false), asset->getLength());
53     SkImageDecoder* decoder = SkImageDecoder::Factory(&stream);
54     if (!decoder) {
55         asset->close();
56         ALOGE("RenderSkinNinePatch::Failed to create an image decoder");
57         return false;
58     }
59 
60     decoder->setSampleSize(1);
61     decoder->setDitherImage(true);
62     decoder->setPreferQualityOverSpeed(false);
63 
64     NinePatchPeeker peeker(decoder);
65 
66     SkAutoTDelete<SkImageDecoder> add(decoder);
67 
68     decoder->setPeeker(&peeker);
69     if (!decoder->decode(&stream, &ninepatch->m_bitmap, prefConfig, mode, true)) {
70         asset->close();
71         ALOGE("RenderSkinNinePatch::Failed to decode nine patch asset");
72         return false;
73     }
74 
75     asset->close();
76     if (!peeker.fPatch) {
77         ALOGE("RenderSkinNinePatch::Patch data not valid");
78         return false;
79     }
80     void** data = &ninepatch->m_serializedPatchData;
81     *data = malloc(peeker.fPatch->serializedSize());
82     peeker.fPatch->serialize(*data);
83     return true;
84 }
85 
DrawNinePatch(SkCanvas * canvas,const SkRect & bounds,const NinePatch & patch)86 void RenderSkinNinePatch::DrawNinePatch(SkCanvas* canvas, const SkRect& bounds,
87                                         const NinePatch& patch) {
88     Res_png_9patch* data = Res_png_9patch::deserialize(patch.m_serializedPatchData);
89 
90     // if the NinePatch is bigger than the destination on a given axis the default
91     // decoder will not stretch properly, therefore we fall back to skia's decoder
92     // which if needed will down-sample and draw the bitmap as best as possible.
93     if (patch.m_bitmap.width() >= bounds.width() || patch.m_bitmap.height() >= bounds.height()) {
94 
95         SkPaint defaultPaint;
96         // matches default dither in NinePatchDrawable.java.
97         defaultPaint.setDither(true);
98         SkNinePatch::DrawMesh(canvas, bounds, patch.m_bitmap,
99                               data->xDivs, data->numXDivs,
100                               data->yDivs, data->numYDivs,
101                               &defaultPaint);
102     } else {
103         NinePatch_Draw(canvas, bounds, patch.m_bitmap, *data, 0, 0);
104     }
105 }
106