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