OSDN Git Service

Merge "Move some VPN logic out of ConnectivityService"
[android-x86/frameworks-base.git] / libs / hwui / SkiaCanvasProxy.cpp
1 /*
2  * Copyright (C) 2015 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 "SkiaCanvasProxy.h"
18
19 #include <memory>
20
21 #include <log/log.h>
22
23 #include <SkPatchUtils.h>
24 #include <SkPaint.h>
25 #include <SkPath.h>
26 #include <SkPixelRef.h>
27 #include <SkRect.h>
28 #include <SkRRect.h>
29
30 namespace android {
31 namespace uirenderer {
32
33 SkiaCanvasProxy::SkiaCanvasProxy(Canvas* canvas, bool filterHwuiCalls)
34         : INHERITED(canvas->width(), canvas->height())
35         , mCanvas(canvas)
36         , mFilterHwuiCalls(filterHwuiCalls) {}
37
38 void SkiaCanvasProxy::onDrawPaint(const SkPaint& paint) {
39     mCanvas->drawPaint(paint);
40 }
41
42 void SkiaCanvasProxy::onDrawPoints(PointMode pointMode, size_t count, const SkPoint pts[],
43         const SkPaint& paint) {
44     if (!pts || count == 0) {
45         return;
46     }
47
48     // convert the SkPoints into floats
49     static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
50     const size_t floatCount = count << 1;
51     const float* floatArray = &pts[0].fX;
52
53     switch (pointMode) {
54         case kPoints_PointMode: {
55             mCanvas->drawPoints(floatArray, floatCount, paint);
56             break;
57         }
58         case kLines_PointMode: {
59             mCanvas->drawLines(floatArray, floatCount, paint);
60             break;
61         }
62         case kPolygon_PointMode: {
63             SkPaint strokedPaint(paint);
64             strokedPaint.setStyle(SkPaint::kStroke_Style);
65
66             SkPath path;
67             for (size_t i = 0; i < count - 1; i++) {
68                 path.moveTo(pts[i]);
69                 path.lineTo(pts[i+1]);
70                 this->drawPath(path, strokedPaint);
71                 path.rewind();
72             }
73             break;
74         }
75         default:
76             LOG_ALWAYS_FATAL("Unknown point type");
77     }
78 }
79
80 void SkiaCanvasProxy::onDrawOval(const SkRect& rect, const SkPaint& paint) {
81     mCanvas->drawOval(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, paint);
82 }
83
84 void SkiaCanvasProxy::onDrawRect(const SkRect& rect, const SkPaint& paint) {
85     mCanvas->drawRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, paint);
86 }
87
88 void SkiaCanvasProxy::onDrawRRect(const SkRRect& roundRect, const SkPaint& paint) {
89     if (!roundRect.isComplex()) {
90         const SkRect& rect = roundRect.rect();
91         SkVector radii = roundRect.getSimpleRadii();
92         mCanvas->drawRoundRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
93                                radii.fX, radii.fY, paint);
94     } else {
95         SkPath path;
96         path.addRRect(roundRect);
97         mCanvas->drawPath(path, paint);
98     }
99 }
100
101 void SkiaCanvasProxy::onDrawPath(const SkPath& path, const SkPaint& paint) {
102     mCanvas->drawPath(path, paint);
103 }
104
105 void SkiaCanvasProxy::onDrawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
106         const SkPaint* paint) {
107     SkPixelRef* pxRef = bitmap.pixelRef();
108
109     // HWUI doesn't support extractSubset(), so convert any subsetted bitmap into
110     // a drawBitmapRect(); pass through an un-subsetted bitmap.
111     if (pxRef && bitmap.dimensions() != pxRef->info().dimensions()) {
112         SkBitmap fullBitmap;
113         fullBitmap.setInfo(pxRef->info());
114         fullBitmap.setPixelRef(pxRef, 0, 0);
115         SkIPoint origin = bitmap.pixelRefOrigin();
116         mCanvas->drawBitmap(fullBitmap, origin.fX, origin.fY,
117                             origin.fX + bitmap.dimensions().width(),
118                             origin.fY + bitmap.dimensions().height(),
119                             left, top,
120                             left + bitmap.dimensions().width(),
121                             top + bitmap.dimensions().height(),
122                             paint);
123     } else {
124         mCanvas->drawBitmap(bitmap, left, top, paint);
125     }
126 }
127
128 void SkiaCanvasProxy::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* srcPtr,
129         const SkRect& dst, const SkPaint* paint, SrcRectConstraint) {
130     SkRect src = (srcPtr) ? *srcPtr : SkRect::MakeWH(bitmap.width(), bitmap.height());
131     // TODO: if bitmap is a subset, do we need to add pixelRefOrigin to src?
132     mCanvas->drawBitmap(bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom,
133                         dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint);
134 }
135
136 void SkiaCanvasProxy::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
137         const SkRect& dst, const SkPaint*) {
138     //TODO make nine-patch drawing a method on Canvas.h
139     SkDEBUGFAIL("SkiaCanvasProxy::onDrawBitmapNine is not yet supported");
140 }
141
142 void SkiaCanvasProxy::onDrawVertices(VertexMode mode, int vertexCount, const SkPoint vertices[],
143         const SkPoint texs[], const SkColor colors[], SkXfermode*, const uint16_t indices[],
144         int indexCount, const SkPaint& paint) {
145     if (mFilterHwuiCalls) {
146         return;
147     }
148     // convert the SkPoints into floats
149     static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
150     const int floatCount = vertexCount << 1;
151     const float* vArray = &vertices[0].fX;
152     const float* tArray = (texs) ? &texs[0].fX : NULL;
153     const int* cArray = (colors) ? (int*)colors : NULL;
154     mCanvas->drawVertices(mode, floatCount, vArray, tArray, cArray, indices, indexCount, paint);
155 }
156
157 SkSurface* SkiaCanvasProxy::onNewSurface(const SkImageInfo&, const SkSurfaceProps&) {
158     SkDEBUGFAIL("SkiaCanvasProxy::onNewSurface is not supported");
159     return NULL;
160 }
161
162 void SkiaCanvasProxy::willSave() {
163     mCanvas->save(android::SaveFlags::MatrixClip);
164 }
165
166 static inline SaveFlags::Flags saveFlags(SkCanvas::SaveLayerFlags layerFlags) {
167     SaveFlags::Flags saveFlags = 0;
168
169     if (!(layerFlags & SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag)) {
170         saveFlags |= SaveFlags::ClipToLayer;
171     }
172
173     if (!(layerFlags & SkCanvas::kIsOpaque_SaveLayerFlag)) {
174         saveFlags |= SaveFlags::HasAlphaLayer;
175     }
176
177     return saveFlags;
178 }
179
180 SkCanvas::SaveLayerStrategy SkiaCanvasProxy::getSaveLayerStrategy(const SaveLayerRec& saveLayerRec) {
181     SkRect rect;
182     if (saveLayerRec.fBounds) {
183         rect = *saveLayerRec.fBounds;
184     } else if (!mCanvas->getClipBounds(&rect)) {
185         rect = SkRect::MakeEmpty();
186     }
187     mCanvas->saveLayer(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, saveLayerRec.fPaint,
188                        saveFlags(saveLayerRec.fSaveLayerFlags));
189     return SkCanvas::kNoLayer_SaveLayerStrategy;
190 }
191
192 void SkiaCanvasProxy::willRestore() {
193     mCanvas->restore();
194 }
195
196 void SkiaCanvasProxy::didConcat(const SkMatrix& matrix) {
197     mCanvas->concat(matrix);
198 }
199
200 void SkiaCanvasProxy::didSetMatrix(const SkMatrix& matrix) {
201     mCanvas->setMatrix(matrix);
202 }
203
204 void SkiaCanvasProxy::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
205         const SkPaint& paint) {
206     SkPath path;
207     path.addRRect(outer);
208     path.addRRect(inner);
209     path.setFillType(SkPath::kEvenOdd_FillType);
210     this->drawPath(path, paint);
211 }
212
213 /**
214  * Utility class that converts the incoming text & paint from the given encoding
215  * into glyphIDs.
216  */
217 class GlyphIDConverter {
218 public:
219     GlyphIDConverter(const void* text, size_t byteLength, const SkPaint& origPaint) {
220         paint = origPaint;
221         if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) {
222             glyphIDs = (uint16_t*)text;
223             count = byteLength >> 1;
224         } else {
225              // ensure space for one glyph per ID given UTF8 encoding.
226             storage.reset(new uint16_t[byteLength]);
227             glyphIDs = storage.get();
228             count = paint.textToGlyphs(text, byteLength, storage.get());
229             paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
230         }
231     }
232
233     SkPaint paint;
234     uint16_t* glyphIDs;
235     int count;
236 private:
237     std::unique_ptr<uint16_t[]> storage;
238 };
239
240 void SkiaCanvasProxy::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
241         const SkPaint& origPaint) {
242     // convert to glyphIDs if necessary
243     GlyphIDConverter glyphs(text, byteLength, origPaint);
244
245     // compute the glyph positions
246     std::unique_ptr<SkPoint[]> pointStorage(new SkPoint[glyphs.count]);
247     std::unique_ptr<SkScalar[]> glyphWidths(new SkScalar[glyphs.count]);
248     glyphs.paint.getTextWidths(glyphs.glyphIDs, glyphs.count << 1, glyphWidths.get());
249
250     // compute conservative bounds
251     // NOTE: We could call the faster paint.getFontBounds for a less accurate,
252     //       but even more conservative bounds if this  is too slow.
253     SkRect bounds;
254     glyphs.paint.measureText(glyphs.glyphIDs, glyphs.count << 1, &bounds);
255
256     // adjust for non-left alignment
257     if (glyphs.paint.getTextAlign() != SkPaint::kLeft_Align) {
258         SkScalar stop = 0;
259         for (int i = 0; i < glyphs.count; i++) {
260             stop += glyphWidths[i];
261         }
262         if (glyphs.paint.getTextAlign() == SkPaint::kCenter_Align) {
263             stop = SkScalarHalf(stop);
264         }
265         if (glyphs.paint.isVerticalText()) {
266             y -= stop;
267         } else {
268             x -= stop;
269         }
270     }
271
272     // setup the first glyph position and adjust bounds if needed
273     int xBaseline = 0;
274     int yBaseline = 0;
275     if (mCanvas->drawTextAbsolutePos()) {
276         bounds.offset(x,y);
277         xBaseline = x;
278         yBaseline = y;
279     }
280     pointStorage[0].set(xBaseline, yBaseline);
281
282     // setup the remaining glyph positions
283     if (glyphs.paint.isVerticalText()) {
284         for (int i = 1; i < glyphs.count; i++) {
285             pointStorage[i].set(xBaseline, glyphWidths[i-1] + pointStorage[i-1].fY);
286         }
287     } else {
288         for (int i = 1; i < glyphs.count; i++) {
289             pointStorage[i].set(glyphWidths[i-1] + pointStorage[i-1].fX, yBaseline);
290         }
291     }
292
293     static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
294     mCanvas->drawGlyphs(glyphs.glyphIDs, &pointStorage[0].fX, glyphs.count, glyphs.paint,
295                       x, y, bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, 0);
296 }
297
298 void SkiaCanvasProxy::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
299         const SkPaint& origPaint) {
300     // convert to glyphIDs if necessary
301     GlyphIDConverter glyphs(text, byteLength, origPaint);
302
303     // convert to relative positions if necessary
304     int x, y;
305     const SkPoint* posArray;
306     std::unique_ptr<SkPoint[]> pointStorage;
307     if (mCanvas->drawTextAbsolutePos()) {
308         x = 0;
309         y = 0;
310         posArray = pos;
311     } else {
312         x = pos[0].fX;
313         y = pos[0].fY;
314         pointStorage.reset(new SkPoint[glyphs.count]);
315         for (int i = 0; i < glyphs.count; i++) {
316             pointStorage[i].fX = pos[i].fX - x;
317             pointStorage[i].fY = pos[i].fY - y;
318         }
319         posArray = pointStorage.get();
320     }
321
322     // Compute conservative bounds.  If the content has already been processed
323     // by Minikin then it had already computed these bounds.  Unfortunately,
324     // there is no way to capture those bounds as part of the Skia drawPosText
325     // API so we need to do that computation again here.
326     SkRect bounds;
327     for (int i = 0; i < glyphs.count; i++) {
328         SkRect glyphBounds;
329         glyphs.paint.measureText(&glyphs.glyphIDs[i], sizeof(uint16_t), &glyphBounds);
330         glyphBounds.offset(pos[i].fX, pos[i].fY);
331         bounds.join(glyphBounds);
332     }
333
334     static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
335     mCanvas->drawGlyphs(glyphs.glyphIDs, &posArray[0].fX, glyphs.count, glyphs.paint, x, y,
336                       bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, 0);
337 }
338
339 void SkiaCanvasProxy::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
340         SkScalar constY, const SkPaint& paint) {
341     const size_t pointCount = byteLength >> 1;
342     std::unique_ptr<SkPoint[]> pts(new SkPoint[pointCount]);
343     for (size_t i = 0; i < pointCount; i++) {
344         pts[i].set(xpos[i], constY);
345     }
346     this->onDrawPosText(text, byteLength, pts.get(), paint);
347 }
348
349 void SkiaCanvasProxy::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
350         const SkMatrix* matrix, const SkPaint& origPaint) {
351     // convert to glyphIDs if necessary
352     GlyphIDConverter glyphs(text, byteLength, origPaint);
353     mCanvas->drawGlyphsOnPath(glyphs.glyphIDs, glyphs.count, path, 0, 0, glyphs.paint);
354 }
355
356 void SkiaCanvasProxy::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
357         const SkPaint& paint) {
358     SkDEBUGFAIL("SkiaCanvasProxy::onDrawTextBlob is not supported");
359 }
360
361 void SkiaCanvasProxy::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
362         const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
363     if (mFilterHwuiCalls) {
364         return;
365     }
366     SkPatchUtils::VertexData data;
367
368     SkMatrix matrix;
369     mCanvas->getMatrix(&matrix);
370     SkISize lod = SkPatchUtils::GetLevelOfDetail(cubics, &matrix);
371
372     // It automatically adjusts lodX and lodY in case it exceeds the number of indices.
373     // If it fails to generate the vertices, then we do not draw.
374     if (SkPatchUtils::getVertexData(&data, cubics, colors, texCoords, lod.width(), lod.height())) {
375         this->drawVertices(SkCanvas::kTriangles_VertexMode, data.fVertexCount, data.fPoints,
376                            data.fTexCoords, data.fColors, xmode, data.fIndices, data.fIndexCount,
377                            paint);
378     }
379 }
380
381 void SkiaCanvasProxy::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle) {
382     mCanvas->clipRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, op);
383 }
384
385 void SkiaCanvasProxy::onClipRRect(const SkRRect& roundRect, SkRegion::Op op, ClipEdgeStyle) {
386     SkPath path;
387     path.addRRect(roundRect);
388     mCanvas->clipPath(&path, op);
389 }
390
391 void SkiaCanvasProxy::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle) {
392     mCanvas->clipPath(&path, op);
393 }
394
395 void SkiaCanvasProxy::onClipRegion(const SkRegion& region, SkRegion::Op op) {
396     mCanvas->clipRegion(&region, op);
397 }
398
399 }; // namespace uirenderer
400 }; // namespace android