blob: 5978abc9efaaa17cc65a47c86bd7f429e344a49f [file] [log] [blame]
Derek Sollenberger1db141f2014-12-16 08:37:20 -05001/*
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
sergeyvaed7f582016-10-14 16:30:21 -070019#include "hwui/Bitmap.h"
20
Derek Sollenberger1db141f2014-12-16 08:37:20 -050021#include <cutils/log.h>
22#include <SkPatchUtils.h>
Ben Wagnera11ee3c2015-08-04 11:14:15 -040023#include <SkPaint.h>
24#include <SkPath.h>
Tom Hudson17c5adf2015-06-09 15:46:04 -040025#include <SkPixelRef.h>
Ben Wagnera11ee3c2015-08-04 11:14:15 -040026#include <SkRect.h>
27#include <SkRRect.h>
Yuqian Liafc221492016-07-18 13:07:42 -040028#include <SkRSXform.h>
Matt Sarett79fc3b12016-03-24 11:02:44 -040029#include <SkSurface.h>
Derek Sollenberger09bd6c22016-11-03 12:54:06 -040030#include <SkTextBlobRunIterator.h>
Derek Sollenberger1db141f2014-12-16 08:37:20 -050031
Ben Wagner6bbf68d2015-08-19 11:26:06 -040032#include <memory>
33
Derek Sollenberger1db141f2014-12-16 08:37:20 -050034namespace android {
35namespace uirenderer {
36
Tom Hudsonb1476ae2015-03-05 10:30:18 -050037SkiaCanvasProxy::SkiaCanvasProxy(Canvas* canvas, bool filterHwuiCalls)
Derek Sollenberger1db141f2014-12-16 08:37:20 -050038 : INHERITED(canvas->width(), canvas->height())
Tom Hudsonb1476ae2015-03-05 10:30:18 -050039 , mCanvas(canvas)
40 , mFilterHwuiCalls(filterHwuiCalls) {}
Derek Sollenberger1db141f2014-12-16 08:37:20 -050041
42void SkiaCanvasProxy::onDrawPaint(const SkPaint& paint) {
43 mCanvas->drawPaint(paint);
44}
45
46void SkiaCanvasProxy::onDrawPoints(PointMode pointMode, size_t count, const SkPoint pts[],
47 const SkPaint& paint) {
Tom Hudsonb1476ae2015-03-05 10:30:18 -050048 if (!pts || count == 0) {
49 return;
50 }
51
Derek Sollenberger1db141f2014-12-16 08:37:20 -050052 // convert the SkPoints into floats
Ben Wagnere3a40ea2015-08-19 15:49:37 -040053 static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
Derek Sollenberger1db141f2014-12-16 08:37:20 -050054 const size_t floatCount = count << 1;
55 const float* floatArray = &pts[0].fX;
56
57 switch (pointMode) {
58 case kPoints_PointMode: {
59 mCanvas->drawPoints(floatArray, floatCount, paint);
60 break;
61 }
62 case kLines_PointMode: {
63 mCanvas->drawLines(floatArray, floatCount, paint);
64 break;
65 }
66 case kPolygon_PointMode: {
67 SkPaint strokedPaint(paint);
68 strokedPaint.setStyle(SkPaint::kStroke_Style);
69
70 SkPath path;
71 for (size_t i = 0; i < count - 1; i++) {
72 path.moveTo(pts[i]);
73 path.lineTo(pts[i+1]);
74 this->drawPath(path, strokedPaint);
75 path.rewind();
76 }
77 break;
78 }
79 default:
80 LOG_ALWAYS_FATAL("Unknown point type");
81 }
82}
83
84void SkiaCanvasProxy::onDrawOval(const SkRect& rect, const SkPaint& paint) {
85 mCanvas->drawOval(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, paint);
86}
87
88void SkiaCanvasProxy::onDrawRect(const SkRect& rect, const SkPaint& paint) {
89 mCanvas->drawRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, paint);
90}
91
92void SkiaCanvasProxy::onDrawRRect(const SkRRect& roundRect, const SkPaint& paint) {
93 if (!roundRect.isComplex()) {
94 const SkRect& rect = roundRect.rect();
95 SkVector radii = roundRect.getSimpleRadii();
96 mCanvas->drawRoundRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
97 radii.fX, radii.fY, paint);
98 } else {
99 SkPath path;
100 path.addRRect(roundRect);
101 mCanvas->drawPath(path, paint);
102 }
103}
104
105void SkiaCanvasProxy::onDrawPath(const SkPath& path, const SkPaint& paint) {
106 mCanvas->drawPath(path, paint);
107}
108
109void SkiaCanvasProxy::onDrawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
110 const SkPaint* paint) {
sergeyvfc9999502016-10-17 13:07:38 -0700111 sk_sp<Bitmap> hwuiBitmap = Bitmap::createFrom(bitmap.info(), *bitmap.pixelRef());
Tom Hudson17c5adf2015-06-09 15:46:04 -0400112 // HWUI doesn't support extractSubset(), so convert any subsetted bitmap into
113 // a drawBitmapRect(); pass through an un-subsetted bitmap.
sergeyvfc9999502016-10-17 13:07:38 -0700114 if (hwuiBitmap && bitmap.dimensions() != hwuiBitmap->info().dimensions()) {
Tom Hudson17c5adf2015-06-09 15:46:04 -0400115 SkIPoint origin = bitmap.pixelRefOrigin();
sergeyvfc9999502016-10-17 13:07:38 -0700116 mCanvas->drawBitmap(*hwuiBitmap, origin.fX, origin.fY,
Tom Hudson17c5adf2015-06-09 15:46:04 -0400117 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 {
sergeyvaed7f582016-10-14 16:30:21 -0700124 mCanvas->drawBitmap(*hwuiBitmap, left, top, paint);
Tom Hudson17c5adf2015-06-09 15:46:04 -0400125 }
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500126}
127
sergeyvfc9999502016-10-17 13:07:38 -0700128void SkiaCanvasProxy::onDrawBitmapRect(const SkBitmap& skBitmap, const SkRect* srcPtr,
Leon Scroggins IIIf35b9892015-07-31 10:38:40 -0400129 const SkRect& dst, const SkPaint* paint, SrcRectConstraint) {
sergeyvfc9999502016-10-17 13:07:38 -0700130 SkRect src = (srcPtr) ? *srcPtr : SkRect::MakeWH(skBitmap.width(), skBitmap.height());
Tom Hudson17c5adf2015-06-09 15:46:04 -0400131 // TODO: if bitmap is a subset, do we need to add pixelRefOrigin to src?
sergeyvfc9999502016-10-17 13:07:38 -0700132 Bitmap* bitmap = reinterpret_cast<Bitmap*>(skBitmap.pixelRef());
133 mCanvas->drawBitmap(*bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom,
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500134 dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint);
135}
136
137void SkiaCanvasProxy::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
138 const SkRect& dst, const SkPaint*) {
139 //TODO make nine-patch drawing a method on Canvas.h
140 SkDEBUGFAIL("SkiaCanvasProxy::onDrawBitmapNine is not yet supported");
141}
142
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500143void SkiaCanvasProxy::onDrawVertices(VertexMode mode, int vertexCount, const SkPoint vertices[],
Mike Reedc2f31df2016-10-28 17:21:45 -0400144 const SkPoint texs[], const SkColor colors[], SkBlendMode, const uint16_t indices[],
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500145 int indexCount, const SkPaint& paint) {
Mike Reedc2f31df2016-10-28 17:21:45 -0400146 // TODO: should we pass through blendmode
Tom Hudsonb1476ae2015-03-05 10:30:18 -0500147 if (mFilterHwuiCalls) {
148 return;
149 }
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500150 // convert the SkPoints into floats
Ben Wagnere3a40ea2015-08-19 15:49:37 -0400151 static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500152 const int floatCount = vertexCount << 1;
153 const float* vArray = &vertices[0].fX;
154 const float* tArray = (texs) ? &texs[0].fX : NULL;
155 const int* cArray = (colors) ? (int*)colors : NULL;
156 mCanvas->drawVertices(mode, floatCount, vArray, tArray, cArray, indices, indexCount, paint);
157}
158
Matt Sarett79fc3b12016-03-24 11:02:44 -0400159sk_sp<SkSurface> SkiaCanvasProxy::onNewSurface(const SkImageInfo&, const SkSurfaceProps&) {
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500160 SkDEBUGFAIL("SkiaCanvasProxy::onNewSurface is not supported");
161 return NULL;
162}
163
164void SkiaCanvasProxy::willSave() {
Florin Malitaeecff562015-12-21 10:43:01 -0500165 mCanvas->save(android::SaveFlags::MatrixClip);
166}
167
168static inline SaveFlags::Flags saveFlags(SkCanvas::SaveLayerFlags layerFlags) {
169 SaveFlags::Flags saveFlags = 0;
170
171 if (!(layerFlags & SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag)) {
172 saveFlags |= SaveFlags::ClipToLayer;
173 }
174
175 if (!(layerFlags & SkCanvas::kIsOpaque_SaveLayerFlag)) {
176 saveFlags |= SaveFlags::HasAlphaLayer;
177 }
178
179 return saveFlags;
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500180}
181
Leon Scroggins III5518e7c2016-01-04 09:37:42 -0500182SkCanvas::SaveLayerStrategy SkiaCanvasProxy::getSaveLayerStrategy(const SaveLayerRec& saveLayerRec) {
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500183 SkRect rect;
Leon Scroggins III5518e7c2016-01-04 09:37:42 -0500184 if (saveLayerRec.fBounds) {
185 rect = *saveLayerRec.fBounds;
186 } else if (!mCanvas->getClipBounds(&rect)) {
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500187 rect = SkRect::MakeEmpty();
188 }
Leon Scroggins III5518e7c2016-01-04 09:37:42 -0500189 mCanvas->saveLayer(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, saveLayerRec.fPaint,
Florin Malitaeecff562015-12-21 10:43:01 -0500190 saveFlags(saveLayerRec.fSaveLayerFlags));
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500191 return SkCanvas::kNoLayer_SaveLayerStrategy;
192}
193
194void SkiaCanvasProxy::willRestore() {
195 mCanvas->restore();
196}
197
198void SkiaCanvasProxy::didConcat(const SkMatrix& matrix) {
199 mCanvas->concat(matrix);
200}
201
202void SkiaCanvasProxy::didSetMatrix(const SkMatrix& matrix) {
Chris Craik6daa13c2015-08-19 13:32:12 -0700203 mCanvas->setMatrix(matrix);
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500204}
205
206void SkiaCanvasProxy::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
207 const SkPaint& paint) {
208 SkPath path;
209 path.addRRect(outer);
210 path.addRRect(inner);
211 path.setFillType(SkPath::kEvenOdd_FillType);
212 this->drawPath(path, paint);
213}
214
215/**
216 * Utility class that converts the incoming text & paint from the given encoding
217 * into glyphIDs.
218 */
219class GlyphIDConverter {
220public:
221 GlyphIDConverter(const void* text, size_t byteLength, const SkPaint& origPaint) {
222 paint = origPaint;
223 if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) {
224 glyphIDs = (uint16_t*)text;
225 count = byteLength >> 1;
226 } else {
Ben Wagner6bbf68d2015-08-19 11:26:06 -0400227 // ensure space for one glyph per ID given UTF8 encoding.
228 storage.reset(new uint16_t[byteLength]);
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500229 glyphIDs = storage.get();
230 count = paint.textToGlyphs(text, byteLength, storage.get());
231 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
232 }
233 }
234
235 SkPaint paint;
236 uint16_t* glyphIDs;
237 int count;
238private:
Ben Wagner6bbf68d2015-08-19 11:26:06 -0400239 std::unique_ptr<uint16_t[]> storage;
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500240};
241
242void SkiaCanvasProxy::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
243 const SkPaint& origPaint) {
244 // convert to glyphIDs if necessary
245 GlyphIDConverter glyphs(text, byteLength, origPaint);
246
247 // compute the glyph positions
Ben Wagner6bbf68d2015-08-19 11:26:06 -0400248 std::unique_ptr<SkPoint[]> pointStorage(new SkPoint[glyphs.count]);
249 std::unique_ptr<SkScalar[]> glyphWidths(new SkScalar[glyphs.count]);
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500250 glyphs.paint.getTextWidths(glyphs.glyphIDs, glyphs.count << 1, glyphWidths.get());
251
252 // compute conservative bounds
253 // NOTE: We could call the faster paint.getFontBounds for a less accurate,
254 // but even more conservative bounds if this is too slow.
255 SkRect bounds;
256 glyphs.paint.measureText(glyphs.glyphIDs, glyphs.count << 1, &bounds);
257
258 // adjust for non-left alignment
259 if (glyphs.paint.getTextAlign() != SkPaint::kLeft_Align) {
260 SkScalar stop = 0;
261 for (int i = 0; i < glyphs.count; i++) {
262 stop += glyphWidths[i];
263 }
264 if (glyphs.paint.getTextAlign() == SkPaint::kCenter_Align) {
265 stop = SkScalarHalf(stop);
266 }
267 if (glyphs.paint.isVerticalText()) {
268 y -= stop;
269 } else {
270 x -= stop;
271 }
272 }
273
274 // setup the first glyph position and adjust bounds if needed
Tom Hudson806a6f02015-02-19 17:11:32 -0500275 int xBaseline = 0;
276 int yBaseline = 0;
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500277 if (mCanvas->drawTextAbsolutePos()) {
278 bounds.offset(x,y);
Tom Hudson806a6f02015-02-19 17:11:32 -0500279 xBaseline = x;
280 yBaseline = y;
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500281 }
Tom Hudson806a6f02015-02-19 17:11:32 -0500282 pointStorage[0].set(xBaseline, yBaseline);
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500283
284 // setup the remaining glyph positions
285 if (glyphs.paint.isVerticalText()) {
286 for (int i = 1; i < glyphs.count; i++) {
Tom Hudson806a6f02015-02-19 17:11:32 -0500287 pointStorage[i].set(xBaseline, glyphWidths[i-1] + pointStorage[i-1].fY);
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500288 }
289 } else {
290 for (int i = 1; i < glyphs.count; i++) {
Tom Hudson806a6f02015-02-19 17:11:32 -0500291 pointStorage[i].set(glyphWidths[i-1] + pointStorage[i-1].fX, yBaseline);
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500292 }
293 }
294
Ben Wagnere3a40ea2015-08-19 15:49:37 -0400295 static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
sergeyvdccca442016-03-21 15:38:21 -0700296 mCanvas->drawGlyphs(glyphs.glyphIDs, &pointStorage[0].fX, glyphs.count, glyphs.paint,
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500297 x, y, bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, 0);
298}
299
300void SkiaCanvasProxy::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
301 const SkPaint& origPaint) {
302 // convert to glyphIDs if necessary
303 GlyphIDConverter glyphs(text, byteLength, origPaint);
304
305 // convert to relative positions if necessary
306 int x, y;
307 const SkPoint* posArray;
Ben Wagner6bbf68d2015-08-19 11:26:06 -0400308 std::unique_ptr<SkPoint[]> pointStorage;
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500309 if (mCanvas->drawTextAbsolutePos()) {
310 x = 0;
311 y = 0;
312 posArray = pos;
313 } else {
314 x = pos[0].fX;
315 y = pos[0].fY;
Ben Wagner6bbf68d2015-08-19 11:26:06 -0400316 pointStorage.reset(new SkPoint[glyphs.count]);
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500317 for (int i = 0; i < glyphs.count; i++) {
Ben Wagner6bbf68d2015-08-19 11:26:06 -0400318 pointStorage[i].fX = pos[i].fX - x;
319 pointStorage[i].fY = pos[i].fY - y;
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500320 }
Ben Wagner6bbf68d2015-08-19 11:26:06 -0400321 posArray = pointStorage.get();
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500322 }
323
Derek Sollenberger35934cc2016-03-23 14:59:10 -0400324 // Compute conservative bounds. If the content has already been processed
325 // by Minikin then it had already computed these bounds. Unfortunately,
326 // there is no way to capture those bounds as part of the Skia drawPosText
327 // API so we need to do that computation again here.
Stan Ilievd84d2ee2016-07-25 13:32:25 -0400328 SkRect bounds = SkRect::MakeEmpty();
Derek Sollenberger35934cc2016-03-23 14:59:10 -0400329 for (int i = 0; i < glyphs.count; i++) {
Stan Ilievd84d2ee2016-07-25 13:32:25 -0400330 SkRect glyphBounds = SkRect::MakeEmpty();
Derek Sollenberger35934cc2016-03-23 14:59:10 -0400331 glyphs.paint.measureText(&glyphs.glyphIDs[i], sizeof(uint16_t), &glyphBounds);
332 glyphBounds.offset(pos[i].fX, pos[i].fY);
333 bounds.join(glyphBounds);
334 }
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500335
Ben Wagnere3a40ea2015-08-19 15:49:37 -0400336 static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
sergeyvdccca442016-03-21 15:38:21 -0700337 mCanvas->drawGlyphs(glyphs.glyphIDs, &posArray[0].fX, glyphs.count, glyphs.paint, x, y,
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500338 bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, 0);
339}
340
341void SkiaCanvasProxy::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
342 SkScalar constY, const SkPaint& paint) {
343 const size_t pointCount = byteLength >> 1;
Ben Wagner6bbf68d2015-08-19 11:26:06 -0400344 std::unique_ptr<SkPoint[]> pts(new SkPoint[pointCount]);
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500345 for (size_t i = 0; i < pointCount; i++) {
346 pts[i].set(xpos[i], constY);
347 }
Ben Wagner6bbf68d2015-08-19 11:26:06 -0400348 this->onDrawPosText(text, byteLength, pts.get(), paint);
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500349}
350
351void SkiaCanvasProxy::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
352 const SkMatrix* matrix, const SkPaint& origPaint) {
Yuqian Liafc221492016-07-18 13:07:42 -0400353 SkDEBUGFAIL("SkiaCanvasProxy::onDrawTextOnPath is not supported");
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500354}
355
Yuqian Liafc221492016-07-18 13:07:42 -0400356void SkiaCanvasProxy::onDrawTextRSXform(const void* text, size_t byteLength,
357 const SkRSXform xform[], const SkRect* cullRect, const SkPaint& paint) {
358 GlyphIDConverter glyphs(text, byteLength, paint); // Just get count
359 SkMatrix localM, currM, origM;
360 mCanvas->getMatrix(&currM);
361 origM = currM;
362 for (int i = 0; i < glyphs.count; i++) {
363 localM.setRSXform(*xform++);
364 currM.setConcat(origM, localM);
365 mCanvas->setMatrix(currM);
366 this->onDrawText((char*)text + (byteLength / glyphs.count * i),
367 byteLength / glyphs.count, 0, 0, paint);
368 }
369 mCanvas->setMatrix(origM);
370}
371
372
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500373void SkiaCanvasProxy::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
374 const SkPaint& paint) {
Derek Sollenberger09bd6c22016-11-03 12:54:06 -0400375 SkPaint runPaint = paint;
376
377 SkTextBlobRunIterator it(blob);
378 for (;!it.done(); it.next()) {
379 size_t textLen = it.glyphCount() * sizeof(uint16_t);
380 const SkPoint& offset = it.offset();
381 // applyFontToPaint() always overwrites the exact same attributes,
382 // so it is safe to not re-seed the paint for this reason.
383 it.applyFontToPaint(&runPaint);
384
385 switch (it.positioning()) {
386 case SkTextBlob::kDefault_Positioning:
387 this->drawText(it.glyphs(), textLen, x + offset.x(), y + offset.y(), runPaint);
388 break;
389 case SkTextBlob::kHorizontal_Positioning: {
390 std::unique_ptr<SkPoint[]> pts(new SkPoint[it.glyphCount()]);
391 for (size_t i = 0; i < it.glyphCount(); i++) {
392 pts[i].set(x + offset.x() + it.pos()[i], y + offset.y());
393 }
394 this->drawPosText(it.glyphs(), textLen, pts.get(), runPaint);
395 break;
396 }
397 case SkTextBlob::kFull_Positioning: {
398 std::unique_ptr<SkPoint[]> pts(new SkPoint[it.glyphCount()]);
399 for (size_t i = 0; i < it.glyphCount(); i++) {
400 const size_t xIndex = i*2;
401 const size_t yIndex = xIndex + 1;
402 pts[i].set(x + offset.x() + it.pos()[xIndex], y + offset.y() + it.pos()[yIndex]);
403 }
404 this->drawPosText(it.glyphs(), textLen, pts.get(), runPaint);
405 break;
406 }
407 default:
408 SkFAIL("unhandled positioning mode");
409 }
410 }
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500411}
412
413void SkiaCanvasProxy::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
Mike Reedc2f31df2016-10-28 17:21:45 -0400414 const SkPoint texCoords[4], SkBlendMode bmode, const SkPaint& paint) {
Tom Hudsonb1476ae2015-03-05 10:30:18 -0500415 if (mFilterHwuiCalls) {
416 return;
417 }
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500418 SkPatchUtils::VertexData data;
419
420 SkMatrix matrix;
421 mCanvas->getMatrix(&matrix);
422 SkISize lod = SkPatchUtils::GetLevelOfDetail(cubics, &matrix);
423
424 // It automatically adjusts lodX and lodY in case it exceeds the number of indices.
425 // If it fails to generate the vertices, then we do not draw.
426 if (SkPatchUtils::getVertexData(&data, cubics, colors, texCoords, lod.width(), lod.height())) {
427 this->drawVertices(SkCanvas::kTriangles_VertexMode, data.fVertexCount, data.fPoints,
Mike Reedc2f31df2016-10-28 17:21:45 -0400428 data.fTexCoords, data.fColors, bmode, data.fIndices, data.fIndexCount,
Derek Sollenberger1db141f2014-12-16 08:37:20 -0500429 paint);
430 }
431}
432
433void SkiaCanvasProxy::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle) {
434 mCanvas->clipRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, op);
435}
436
437void SkiaCanvasProxy::onClipRRect(const SkRRect& roundRect, SkRegion::Op op, ClipEdgeStyle) {
438 SkPath path;
439 path.addRRect(roundRect);
440 mCanvas->clipPath(&path, op);
441}
442
443void SkiaCanvasProxy::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle) {
444 mCanvas->clipPath(&path, op);
445}
446
447void SkiaCanvasProxy::onClipRegion(const SkRegion& region, SkRegion::Op op) {
448 mCanvas->clipRegion(&region, op);
449}
450
451}; // namespace uirenderer
452}; // namespace android