1 /*
2 * Copyright (C) 2014 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 "SkiaCanvas.h"
18
19 #include "CanvasProperty.h"
20 #include "NinePatchUtils.h"
21 #include "VectorDrawable.h"
22 #include "hwui/Bitmap.h"
23 #include "hwui/MinikinUtils.h"
24 #include "pipeline/skia/AnimatedDrawables.h"
25
26 #include <SkCanvasStateUtils.h>
27 #include <SkColorSpaceXformCanvas.h>
28 #include <SkDrawable.h>
29 #include <SkDeque.h>
30 #include <SkDrawFilter.h>
31 #include <SkGraphics.h>
32 #include <SkImage.h>
33 #include <SkImagePriv.h>
34 #include <SkRSXform.h>
35 #include <SkShader.h>
36 #include <SkTemplates.h>
37 #include <SkTextBlob.h>
38
39 #include <memory>
40
41 namespace android {
42
43 using uirenderer::PaintUtils;
44
create_canvas(const SkBitmap & bitmap)45 Canvas* Canvas::create_canvas(const SkBitmap& bitmap) {
46 return new SkiaCanvas(bitmap);
47 }
48
create_canvas(SkCanvas * skiaCanvas,XformToSRGB xformToSRGB)49 Canvas* Canvas::create_canvas(SkCanvas* skiaCanvas, XformToSRGB xformToSRGB) {
50 return new SkiaCanvas(skiaCanvas, xformToSRGB);
51 }
52
SkiaCanvas()53 SkiaCanvas::SkiaCanvas() {}
54
SkiaCanvas(SkCanvas * canvas,XformToSRGB xformToSRGB)55 SkiaCanvas::SkiaCanvas(SkCanvas* canvas, XformToSRGB xformToSRGB)
56 : mCanvas(canvas)
57 {
58 LOG_ALWAYS_FATAL_IF(XformToSRGB::kImmediate == xformToSRGB);
59 }
60
SkiaCanvas(const SkBitmap & bitmap)61 SkiaCanvas::SkiaCanvas(const SkBitmap& bitmap) {
62 sk_sp<SkColorSpace> cs = bitmap.refColorSpace();
63 mCanvasOwned =
64 std::unique_ptr<SkCanvas>(new SkCanvas(bitmap, SkCanvas::ColorBehavior::kLegacy));
65 mCanvasWrapper = SkCreateColorSpaceXformCanvas(mCanvasOwned.get(),
66 cs == nullptr ? SkColorSpace::MakeSRGB() : std::move(cs));
67 mCanvas = mCanvasWrapper.get();
68 }
69
~SkiaCanvas()70 SkiaCanvas::~SkiaCanvas() {}
71
reset(SkCanvas * skiaCanvas)72 void SkiaCanvas::reset(SkCanvas* skiaCanvas) {
73 if (mCanvas != skiaCanvas) {
74 mCanvas = skiaCanvas;
75 mCanvasOwned.reset();
76 }
77 mSaveStack.reset(nullptr);
78 mHighContrastText = false;
79 }
80
81 // ----------------------------------------------------------------------------
82 // Canvas state operations: Replace Bitmap
83 // ----------------------------------------------------------------------------
84
setBitmap(const SkBitmap & bitmap)85 void SkiaCanvas::setBitmap(const SkBitmap& bitmap) {
86 sk_sp<SkColorSpace> cs = bitmap.refColorSpace();
87 std::unique_ptr<SkCanvas> newCanvas =
88 std::unique_ptr<SkCanvas>(new SkCanvas(bitmap, SkCanvas::ColorBehavior::kLegacy));
89 std::unique_ptr<SkCanvas> newCanvasWrapper = SkCreateColorSpaceXformCanvas(newCanvas.get(),
90 cs == nullptr ? SkColorSpace::MakeSRGB() : std::move(cs));
91
92 // deletes the previously owned canvas (if any)
93 mCanvasOwned = std::move(newCanvas);
94 mCanvasWrapper = std::move(newCanvasWrapper);
95 mCanvas = mCanvasWrapper.get();
96
97 // clean up the old save stack
98 mSaveStack.reset(nullptr);
99 }
100
101 // ----------------------------------------------------------------------------
102 // Canvas state operations
103 // ----------------------------------------------------------------------------
104
isOpaque()105 bool SkiaCanvas::isOpaque() {
106 return mCanvas->imageInfo().isOpaque();
107 }
108
width()109 int SkiaCanvas::width() {
110 return mCanvas->imageInfo().width();
111 }
112
height()113 int SkiaCanvas::height() {
114 return mCanvas->imageInfo().height();
115 }
116
117 // ----------------------------------------------------------------------------
118 // Canvas state operations: Save (layer)
119 // ----------------------------------------------------------------------------
120
getSaveCount() const121 int SkiaCanvas::getSaveCount() const {
122 return mCanvas->getSaveCount();
123 }
124
save(SaveFlags::Flags flags)125 int SkiaCanvas::save(SaveFlags::Flags flags) {
126 int count = mCanvas->save();
127 recordPartialSave(flags);
128 return count;
129 }
130
131 // The SkiaCanvas::restore operation layers on the capability to preserve
132 // either (or both) the matrix and/or clip state after a SkCanvas::restore
133 // operation. It does this by explicitly saving off the clip & matrix state
134 // when requested and playing it back after the SkCanvas::restore.
restore()135 void SkiaCanvas::restore() {
136 const auto* rec = this->currentSaveRec();
137 if (!rec) {
138 // Fast path - no record for this frame.
139 mCanvas->restore();
140 return;
141 }
142
143 bool preserveMatrix = !(rec->saveFlags & SaveFlags::Matrix);
144 bool preserveClip = !(rec->saveFlags & SaveFlags::Clip);
145
146 SkMatrix savedMatrix;
147 if (preserveMatrix) {
148 savedMatrix = mCanvas->getTotalMatrix();
149 }
150
151 const size_t clipIndex = rec->clipIndex;
152
153 mCanvas->restore();
154 mSaveStack->pop_back();
155
156 if (preserveMatrix) {
157 mCanvas->setMatrix(savedMatrix);
158 }
159
160 if (preserveClip) {
161 this->applyPersistentClips(clipIndex);
162 }
163 }
164
restoreToCount(int restoreCount)165 void SkiaCanvas::restoreToCount(int restoreCount) {
166 while (mCanvas->getSaveCount() > restoreCount) {
167 this->restore();
168 }
169 }
170
layerFlags(SaveFlags::Flags flags)171 static inline SkCanvas::SaveLayerFlags layerFlags(SaveFlags::Flags flags) {
172 SkCanvas::SaveLayerFlags layerFlags = 0;
173
174 // We intentionally ignore the SaveFlags::HasAlphaLayer and
175 // SkCanvas::kIsOpaque_SaveLayerFlag flags because HWUI ignores it
176 // and our Android client may use it incorrectly.
177 // In Skia, this flag is purely for performance optimization.
178
179 if (!(flags & SaveFlags::ClipToLayer)) {
180 layerFlags |= SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag;
181 }
182
183 return layerFlags;
184 }
185
saveLayer(float left,float top,float right,float bottom,const SkPaint * paint,SaveFlags::Flags flags)186 int SkiaCanvas::saveLayer(float left, float top, float right, float bottom,
187 const SkPaint* paint, SaveFlags::Flags flags) {
188 const SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
189 const SkCanvas::SaveLayerRec rec(&bounds, paint, layerFlags(flags));
190
191 return mCanvas->saveLayer(rec);
192 }
193
saveLayerAlpha(float left,float top,float right,float bottom,int alpha,SaveFlags::Flags flags)194 int SkiaCanvas::saveLayerAlpha(float left, float top, float right, float bottom,
195 int alpha, SaveFlags::Flags flags) {
196 if (static_cast<unsigned>(alpha) < 0xFF) {
197 SkPaint alphaPaint;
198 alphaPaint.setAlpha(alpha);
199 return this->saveLayer(left, top, right, bottom, &alphaPaint, flags);
200 }
201 return this->saveLayer(left, top, right, bottom, nullptr, flags);
202 }
203
204 class SkiaCanvas::Clip {
205 public:
Clip(const SkRect & rect,SkClipOp op,const SkMatrix & m)206 Clip(const SkRect& rect, SkClipOp op, const SkMatrix& m)
207 : mType(Type::Rect), mOp(op), mMatrix(m), mRRect(SkRRect::MakeRect(rect)) {}
Clip(const SkRRect & rrect,SkClipOp op,const SkMatrix & m)208 Clip(const SkRRect& rrect, SkClipOp op, const SkMatrix& m)
209 : mType(Type::RRect), mOp(op), mMatrix(m), mRRect(rrect) {}
Clip(const SkPath & path,SkClipOp op,const SkMatrix & m)210 Clip(const SkPath& path, SkClipOp op, const SkMatrix& m)
211 : mType(Type::Path), mOp(op), mMatrix(m), mPath(&path) {}
212
apply(SkCanvas * canvas) const213 void apply(SkCanvas* canvas) const {
214 canvas->setMatrix(mMatrix);
215 switch (mType) {
216 case Type::Rect:
217 canvas->clipRect(mRRect.rect(), mOp);
218 break;
219 case Type::RRect:
220 canvas->clipRRect(mRRect, mOp);
221 break;
222 case Type::Path:
223 canvas->clipPath(*mPath.get(), mOp);
224 break;
225 }
226 }
227
228 private:
229 enum class Type {
230 Rect,
231 RRect,
232 Path,
233 };
234
235 Type mType;
236 SkClipOp mOp;
237 SkMatrix mMatrix;
238
239 // These are logically a union (tracked separately due to non-POD path).
240 SkTLazy<SkPath> mPath;
241 SkRRect mRRect;
242 };
243
currentSaveRec() const244 const SkiaCanvas::SaveRec* SkiaCanvas::currentSaveRec() const {
245 const SaveRec* rec = mSaveStack
246 ? static_cast<const SaveRec*>(mSaveStack->back())
247 : nullptr;
248 int currentSaveCount = mCanvas->getSaveCount();
249 SkASSERT(!rec || currentSaveCount >= rec->saveCount);
250
251 return (rec && rec->saveCount == currentSaveCount) ? rec : nullptr;
252 }
253
254 // ----------------------------------------------------------------------------
255 // functions to emulate legacy SaveFlags (i.e. independent matrix/clip flags)
256 // ----------------------------------------------------------------------------
257
recordPartialSave(SaveFlags::Flags flags)258 void SkiaCanvas::recordPartialSave(SaveFlags::Flags flags) {
259 // A partial save is a save operation which doesn't capture the full canvas state.
260 // (either SaveFlags::Matrix or SaveFlags::Clip is missing).
261
262 // Mask-out non canvas state bits.
263 flags &= SaveFlags::MatrixClip;
264
265 if (flags == SaveFlags::MatrixClip) {
266 // not a partial save.
267 return;
268 }
269
270 if (!mSaveStack) {
271 mSaveStack.reset(new SkDeque(sizeof(struct SaveRec), 8));
272 }
273
274 SaveRec* rec = static_cast<SaveRec*>(mSaveStack->push_back());
275 rec->saveCount = mCanvas->getSaveCount();
276 rec->saveFlags = flags;
277 rec->clipIndex = mClipStack.size();
278 }
279
280 template <typename T>
recordClip(const T & clip,SkClipOp op)281 void SkiaCanvas::recordClip(const T& clip, SkClipOp op) {
282 // Only need tracking when in a partial save frame which
283 // doesn't restore the clip.
284 const SaveRec* rec = this->currentSaveRec();
285 if (rec && !(rec->saveFlags & SaveFlags::Clip)) {
286 mClipStack.emplace_back(clip, op, mCanvas->getTotalMatrix());
287 }
288 }
289
290 // Applies and optionally removes all clips >= index.
applyPersistentClips(size_t clipStartIndex)291 void SkiaCanvas::applyPersistentClips(size_t clipStartIndex) {
292 SkASSERT(clipStartIndex <= mClipStack.size());
293 const auto begin = mClipStack.cbegin() + clipStartIndex;
294 const auto end = mClipStack.cend();
295
296 // Clip application mutates the CTM.
297 const SkMatrix saveMatrix = mCanvas->getTotalMatrix();
298
299 for (auto clip = begin; clip != end; ++clip) {
300 clip->apply(mCanvas);
301 }
302
303 mCanvas->setMatrix(saveMatrix);
304
305 // If the current/post-restore save rec is also persisting clips, we
306 // leave them on the stack to be reapplied part of the next restore().
307 // Otherwise we're done and just pop them.
308 const auto* rec = this->currentSaveRec();
309 if (!rec || (rec->saveFlags & SaveFlags::Clip)) {
310 mClipStack.erase(begin, end);
311 }
312 }
313
314 // ----------------------------------------------------------------------------
315 // Canvas state operations: Matrix
316 // ----------------------------------------------------------------------------
317
getMatrix(SkMatrix * outMatrix) const318 void SkiaCanvas::getMatrix(SkMatrix* outMatrix) const {
319 *outMatrix = mCanvas->getTotalMatrix();
320 }
321
setMatrix(const SkMatrix & matrix)322 void SkiaCanvas::setMatrix(const SkMatrix& matrix) {
323 mCanvas->setMatrix(matrix);
324 }
325
concat(const SkMatrix & matrix)326 void SkiaCanvas::concat(const SkMatrix& matrix) {
327 mCanvas->concat(matrix);
328 }
329
rotate(float degrees)330 void SkiaCanvas::rotate(float degrees) {
331 mCanvas->rotate(degrees);
332 }
333
scale(float sx,float sy)334 void SkiaCanvas::scale(float sx, float sy) {
335 mCanvas->scale(sx, sy);
336 }
337
skew(float sx,float sy)338 void SkiaCanvas::skew(float sx, float sy) {
339 mCanvas->skew(sx, sy);
340 }
341
translate(float dx,float dy)342 void SkiaCanvas::translate(float dx, float dy) {
343 mCanvas->translate(dx, dy);
344 }
345
346 // ----------------------------------------------------------------------------
347 // Canvas state operations: Clips
348 // ----------------------------------------------------------------------------
349
350 // This function is a mirror of SkCanvas::getClipBounds except that it does
351 // not outset the edge of the clip to account for anti-aliasing. There is
352 // a skia bug to investigate pushing this logic into back into skia.
353 // (see https://code.google.com/p/skia/issues/detail?id=1303)
getClipBounds(SkRect * outRect) const354 bool SkiaCanvas::getClipBounds(SkRect* outRect) const {
355 SkIRect ibounds;
356 if (!mCanvas->getDeviceClipBounds(&ibounds)) {
357 return false;
358 }
359
360 SkMatrix inverse;
361 // if we can't invert the CTM, we can't return local clip bounds
362 if (!mCanvas->getTotalMatrix().invert(&inverse)) {
363 if (outRect) {
364 outRect->setEmpty();
365 }
366 return false;
367 }
368
369 if (NULL != outRect) {
370 SkRect r = SkRect::Make(ibounds);
371 inverse.mapRect(outRect, r);
372 }
373 return true;
374 }
375
quickRejectRect(float left,float top,float right,float bottom) const376 bool SkiaCanvas::quickRejectRect(float left, float top, float right, float bottom) const {
377 SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
378 return mCanvas->quickReject(bounds);
379 }
380
quickRejectPath(const SkPath & path) const381 bool SkiaCanvas::quickRejectPath(const SkPath& path) const {
382 return mCanvas->quickReject(path);
383 }
384
clipRect(float left,float top,float right,float bottom,SkClipOp op)385 bool SkiaCanvas::clipRect(float left, float top, float right, float bottom, SkClipOp op) {
386 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
387 this->recordClip(rect, op);
388 mCanvas->clipRect(rect, op);
389 return !mCanvas->isClipEmpty();
390 }
391
clipPath(const SkPath * path,SkClipOp op)392 bool SkiaCanvas::clipPath(const SkPath* path, SkClipOp op) {
393 this->recordClip(*path, op);
394 mCanvas->clipPath(*path, op);
395 return !mCanvas->isClipEmpty();
396 }
397
398 // ----------------------------------------------------------------------------
399 // Canvas state operations: Filters
400 // ----------------------------------------------------------------------------
401
getDrawFilter()402 SkDrawFilter* SkiaCanvas::getDrawFilter() {
403 return mCanvas->getDrawFilter();
404 }
405
setDrawFilter(SkDrawFilter * drawFilter)406 void SkiaCanvas::setDrawFilter(SkDrawFilter* drawFilter) {
407 mCanvas->setDrawFilter(drawFilter);
408 }
409
410 // ----------------------------------------------------------------------------
411 // Canvas state operations: Capture
412 // ----------------------------------------------------------------------------
413
captureCanvasState() const414 SkCanvasState* SkiaCanvas::captureCanvasState() const {
415 SkCanvas* canvas = mCanvas;
416 if (mCanvasOwned) {
417 // Important to use the underlying SkCanvas, not the wrapper.
418 canvas = mCanvasOwned.get();
419 }
420
421 // Workarounds for http://crbug.com/271096: SW draw only supports
422 // translate & scale transforms, and a simple rectangular clip.
423 // (This also avoids significant wasted time in calling
424 // SkCanvasStateUtils::CaptureCanvasState when the clip is complex).
425 if (!canvas->isClipRect() ||
426 (canvas->getTotalMatrix().getType() &
427 ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask))) {
428 return nullptr;
429 }
430
431 return SkCanvasStateUtils::CaptureCanvasState(canvas);
432 }
433
434 // ----------------------------------------------------------------------------
435 // Canvas draw operations
436 // ----------------------------------------------------------------------------
437
drawColor(int color,SkBlendMode mode)438 void SkiaCanvas::drawColor(int color, SkBlendMode mode) {
439 mCanvas->drawColor(color, mode);
440 }
441
drawPaint(const SkPaint & paint)442 void SkiaCanvas::drawPaint(const SkPaint& paint) {
443 mCanvas->drawPaint(paint);
444 }
445
446 // ----------------------------------------------------------------------------
447 // Canvas draw operations: Geometry
448 // ----------------------------------------------------------------------------
449
drawPoints(const float * points,int count,const SkPaint & paint,SkCanvas::PointMode mode)450 void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint,
451 SkCanvas::PointMode mode) {
452 if (CC_UNLIKELY(count < 2 || paint.nothingToDraw())) return;
453 // convert the floats into SkPoints
454 count >>= 1; // now it is the number of points
455 std::unique_ptr<SkPoint[]> pts(new SkPoint[count]);
456 for (int i = 0; i < count; i++) {
457 pts[i].set(points[0], points[1]);
458 points += 2;
459 }
460 mCanvas->drawPoints(mode, count, pts.get(), paint);
461 }
462
463
drawPoint(float x,float y,const SkPaint & paint)464 void SkiaCanvas::drawPoint(float x, float y, const SkPaint& paint) {
465 mCanvas->drawPoint(x, y, paint);
466 }
467
drawPoints(const float * points,int count,const SkPaint & paint)468 void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint) {
469 this->drawPoints(points, count, paint, SkCanvas::kPoints_PointMode);
470 }
471
drawLine(float startX,float startY,float stopX,float stopY,const SkPaint & paint)472 void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY,
473 const SkPaint& paint) {
474 mCanvas->drawLine(startX, startY, stopX, stopY, paint);
475 }
476
drawLines(const float * points,int count,const SkPaint & paint)477 void SkiaCanvas::drawLines(const float* points, int count, const SkPaint& paint) {
478 if (CC_UNLIKELY(count < 4 || paint.nothingToDraw())) return;
479 this->drawPoints(points, count, paint, SkCanvas::kLines_PointMode);
480 }
481
drawRect(float left,float top,float right,float bottom,const SkPaint & paint)482 void SkiaCanvas::drawRect(float left, float top, float right, float bottom,
483 const SkPaint& paint) {
484 if (CC_UNLIKELY(paint.nothingToDraw())) return;
485 mCanvas->drawRectCoords(left, top, right, bottom, paint);
486
487 }
488
drawRegion(const SkRegion & region,const SkPaint & paint)489 void SkiaCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
490 if (CC_UNLIKELY(paint.nothingToDraw())) return;
491 mCanvas->drawRegion(region, paint);
492 }
493
drawRoundRect(float left,float top,float right,float bottom,float rx,float ry,const SkPaint & paint)494 void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom,
495 float rx, float ry, const SkPaint& paint) {
496 if (CC_UNLIKELY(paint.nothingToDraw())) return;
497 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
498 mCanvas->drawRoundRect(rect, rx, ry, paint);
499 }
500
drawCircle(float x,float y,float radius,const SkPaint & paint)501 void SkiaCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) {
502 if (CC_UNLIKELY(radius <= 0 || paint.nothingToDraw())) return;
503 mCanvas->drawCircle(x, y, radius, paint);
504 }
505
drawOval(float left,float top,float right,float bottom,const SkPaint & paint)506 void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) {
507 if (CC_UNLIKELY(paint.nothingToDraw())) return;
508 SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
509 mCanvas->drawOval(oval, paint);
510 }
511
drawArc(float left,float top,float right,float bottom,float startAngle,float sweepAngle,bool useCenter,const SkPaint & paint)512 void SkiaCanvas::drawArc(float left, float top, float right, float bottom,
513 float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
514 if (CC_UNLIKELY(paint.nothingToDraw())) return;
515 SkRect arc = SkRect::MakeLTRB(left, top, right, bottom);
516 mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, paint);
517 }
518
drawPath(const SkPath & path,const SkPaint & paint)519 void SkiaCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
520 if (CC_UNLIKELY(paint.nothingToDraw())) return;
521 mCanvas->drawPath(path, paint);
522 }
523
drawVertices(SkCanvas::VertexMode vertexMode,int vertexCount,const float * verts,const float * texs,const int * colors,const uint16_t * indices,int indexCount,const SkPaint & paint)524 void SkiaCanvas::drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount,
525 const float* verts, const float* texs, const int* colors,
526 const uint16_t* indices, int indexCount, const SkPaint& paint) {
527 #ifndef SK_SCALAR_IS_FLOAT
528 SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid");
529 #endif
530 const int ptCount = vertexCount >> 1;
531 mCanvas->drawVertices(SkVertices::MakeCopy(vertexMode, ptCount, (SkPoint*)verts,
532 (SkPoint*)texs, (SkColor*)colors,
533 indexCount, indices),
534 SkBlendMode::kModulate, paint);
535 }
536
537 // ----------------------------------------------------------------------------
538 // Canvas draw operations: Bitmaps
539 // ----------------------------------------------------------------------------
540
drawBitmap(Bitmap & bitmap,float left,float top,const SkPaint * paint)541 void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
542 SkBitmap skBitmap;
543 bitmap.getSkBitmap(&skBitmap);
544 mCanvas->drawBitmap(skBitmap, left, top, paint);
545 }
546
drawBitmap(Bitmap & hwuiBitmap,const SkMatrix & matrix,const SkPaint * paint)547 void SkiaCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix, const SkPaint* paint) {
548 SkBitmap bitmap;
549 hwuiBitmap.getSkBitmap(&bitmap);
550 SkAutoCanvasRestore acr(mCanvas, true);
551 mCanvas->concat(matrix);
552 mCanvas->drawBitmap(bitmap, 0, 0, paint);
553 }
554
drawBitmap(Bitmap & hwuiBitmap,float srcLeft,float srcTop,float srcRight,float srcBottom,float dstLeft,float dstTop,float dstRight,float dstBottom,const SkPaint * paint)555 void SkiaCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float srcTop,
556 float srcRight, float srcBottom, float dstLeft, float dstTop,
557 float dstRight, float dstBottom, const SkPaint* paint) {
558 SkBitmap bitmap;
559 hwuiBitmap.getSkBitmap(&bitmap);
560 SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
561 SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
562 mCanvas->drawBitmapRect(bitmap, srcRect, dstRect, paint);
563 }
564
drawBitmapMesh(Bitmap & hwuiBitmap,int meshWidth,int meshHeight,const float * vertices,const int * colors,const SkPaint * paint)565 void SkiaCanvas::drawBitmapMesh(Bitmap& hwuiBitmap, int meshWidth, int meshHeight,
566 const float* vertices, const int* colors, const SkPaint* paint) {
567 SkBitmap bitmap;
568 hwuiBitmap.getSkBitmap(&bitmap);
569 const int ptCount = (meshWidth + 1) * (meshHeight + 1);
570 const int indexCount = meshWidth * meshHeight * 6;
571 uint32_t flags = SkVertices::kHasTexCoords_BuilderFlag;
572 if (colors) {
573 flags |= SkVertices::kHasColors_BuilderFlag;
574 }
575 SkVertices::Builder builder(SkCanvas::kTriangles_VertexMode, ptCount, indexCount, flags);
576 memcpy(builder.positions(), vertices, ptCount * sizeof(SkPoint));
577 if (colors) {
578 memcpy(builder.colors(), colors, ptCount * sizeof(SkColor));
579 }
580 SkPoint* texs = builder.texCoords();
581 uint16_t* indices = builder.indices();
582
583 // cons up texture coordinates and indices
584 {
585 const SkScalar w = SkIntToScalar(bitmap.width());
586 const SkScalar h = SkIntToScalar(bitmap.height());
587 const SkScalar dx = w / meshWidth;
588 const SkScalar dy = h / meshHeight;
589
590 SkPoint* texsPtr = texs;
591 SkScalar y = 0;
592 for (int i = 0; i <= meshHeight; i++) {
593 if (i == meshHeight) {
594 y = h; // to ensure numerically we hit h exactly
595 }
596 SkScalar x = 0;
597 for (int j = 0; j < meshWidth; j++) {
598 texsPtr->set(x, y);
599 texsPtr += 1;
600 x += dx;
601 }
602 texsPtr->set(w, y);
603 texsPtr += 1;
604 y += dy;
605 }
606 SkASSERT(texsPtr - texs == ptCount);
607 }
608
609 // cons up indices
610 {
611 uint16_t* indexPtr = indices;
612 int index = 0;
613 for (int i = 0; i < meshHeight; i++) {
614 for (int j = 0; j < meshWidth; j++) {
615 // lower-left triangle
616 *indexPtr++ = index;
617 *indexPtr++ = index + meshWidth + 1;
618 *indexPtr++ = index + meshWidth + 2;
619 // upper-right triangle
620 *indexPtr++ = index;
621 *indexPtr++ = index + meshWidth + 2;
622 *indexPtr++ = index + 1;
623 // bump to the next cell
624 index += 1;
625 }
626 // bump to the next row
627 index += 1;
628 }
629 SkASSERT(indexPtr - indices == indexCount);
630 }
631
632 // double-check that we have legal indices
633 #ifdef SK_DEBUG
634 {
635 for (int i = 0; i < indexCount; i++) {
636 SkASSERT((unsigned)indices[i] < (unsigned)ptCount);
637 }
638 }
639 #endif
640
641 // cons-up a shader for the bitmap
642 SkPaint tmpPaint;
643 if (paint) {
644 tmpPaint = *paint;
645 }
646
647 sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
648 tmpPaint.setShader(image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode));
649
650 mCanvas->drawVertices(builder.detach(), SkBlendMode::kModulate, tmpPaint);
651 }
652
drawNinePatch(Bitmap & hwuiBitmap,const Res_png_9patch & chunk,float dstLeft,float dstTop,float dstRight,float dstBottom,const SkPaint * paint)653 void SkiaCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk,
654 float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {
655
656 SkBitmap bitmap;
657 hwuiBitmap.getSkBitmap(&bitmap);
658
659 SkCanvas::Lattice lattice;
660 NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
661
662 lattice.fFlags = nullptr;
663 int numFlags = 0;
664 if (chunk.numColors > 0 && chunk.numColors == NinePatchUtils::NumDistinctRects(lattice)) {
665 // We can expect the framework to give us a color for every distinct rect.
666 // Skia requires a flag for every rect.
667 numFlags = (lattice.fXCount + 1) * (lattice.fYCount + 1);
668 }
669
670 SkAutoSTMalloc<25, SkCanvas::Lattice::Flags> flags(numFlags);
671 if (numFlags > 0) {
672 NinePatchUtils::SetLatticeFlags(&lattice, flags.get(), numFlags, chunk);
673 }
674
675 lattice.fBounds = nullptr;
676 SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
677 mCanvas->drawBitmapLattice(bitmap, lattice, dst, paint);
678 }
679
drawVectorDrawable(VectorDrawableRoot * vectorDrawable)680 void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) {
681 vectorDrawable->drawStaging(this);
682 }
683
684 // ----------------------------------------------------------------------------
685 // Canvas draw operations: Text
686 // ----------------------------------------------------------------------------
687
drawGlyphs(const uint16_t * text,const float * positions,int count,const SkPaint & paint,float x,float y,float boundsLeft,float boundsTop,float boundsRight,float boundsBottom,float totalAdvance)688 void SkiaCanvas::drawGlyphs(const uint16_t* text, const float* positions, int count,
689 const SkPaint& paint, float x, float y,
690 float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
691 float totalAdvance) {
692 if (!text || !positions || count <= 0 || paint.nothingToDraw()) return;
693 // Set align to left for drawing, as we don't want individual
694 // glyphs centered or right-aligned; the offset above takes
695 // care of all alignment.
696 SkPaint paintCopy(paint);
697 paintCopy.setTextAlign(SkPaint::kLeft_Align);
698
699 SkRect bounds = SkRect::MakeLTRB(boundsLeft + x, boundsTop + y,
700 boundsRight + x, boundsBottom + y);
701
702 SkTextBlobBuilder builder;
703 const SkTextBlobBuilder::RunBuffer& buffer = builder.allocRunPos(paintCopy, count, &bounds);
704 // TODO: we could reduce the number of memcpy's if the this were exposed further up
705 // in the architecture.
706 memcpy(buffer.glyphs, text, count * sizeof(uint16_t));
707 memcpy(buffer.pos, positions, (count << 1) * sizeof(float));
708
709 sk_sp<SkTextBlob> textBlob(builder.make());
710 mCanvas->drawTextBlob(textBlob, 0, 0, paintCopy);
711 drawTextDecorations(x, y, totalAdvance, paintCopy);
712 }
713
drawLayoutOnPath(const minikin::Layout & layout,float hOffset,float vOffset,const SkPaint & paint,const SkPath & path,size_t start,size_t end)714 void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
715 const SkPaint& paint, const SkPath& path, size_t start, size_t end) {
716 const int N = end - start;
717 SkAutoSTMalloc<1024, uint8_t> storage(N * (sizeof(uint16_t) + sizeof(SkRSXform)));
718 SkRSXform* xform = (SkRSXform*)storage.get();
719 uint16_t* glyphs = (uint16_t*)(xform + N);
720 SkPathMeasure meas(path, false);
721
722 for (size_t i = start; i < end; i++) {
723 glyphs[i - start] = layout.getGlyphId(i);
724 float x = hOffset + layout.getX(i);
725 float y = vOffset + layout.getY(i);
726
727 SkPoint pos;
728 SkVector tan;
729 if (!meas.getPosTan(x, &pos, &tan)) {
730 pos.set(x, y);
731 tan.set(1, 0);
732 }
733 xform[i - start].fSCos = tan.x();
734 xform[i - start].fSSin = tan.y();
735 xform[i - start].fTx = pos.x() - tan.y() * y;
736 xform[i - start].fTy = pos.y() + tan.x() * y;
737 }
738
739 this->asSkCanvas()->drawTextRSXform(glyphs, sizeof(uint16_t) * N, xform, nullptr, paint);
740 }
741
742 // ----------------------------------------------------------------------------
743 // Canvas draw operations: Animations
744 // ----------------------------------------------------------------------------
745
drawRoundRect(uirenderer::CanvasPropertyPrimitive * left,uirenderer::CanvasPropertyPrimitive * top,uirenderer::CanvasPropertyPrimitive * right,uirenderer::CanvasPropertyPrimitive * bottom,uirenderer::CanvasPropertyPrimitive * rx,uirenderer::CanvasPropertyPrimitive * ry,uirenderer::CanvasPropertyPaint * paint)746 void SkiaCanvas::drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
747 uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
748 uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
749 uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) {
750 sk_sp<uirenderer::skiapipeline::AnimatedRoundRect> drawable(
751 new uirenderer::skiapipeline::AnimatedRoundRect(left, top, right, bottom, rx, ry, paint));
752 mCanvas->drawDrawable(drawable.get());
753 }
754
drawCircle(uirenderer::CanvasPropertyPrimitive * x,uirenderer::CanvasPropertyPrimitive * y,uirenderer::CanvasPropertyPrimitive * radius,uirenderer::CanvasPropertyPaint * paint)755 void SkiaCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x, uirenderer::CanvasPropertyPrimitive* y,
756 uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPaint* paint) {
757 sk_sp<uirenderer::skiapipeline::AnimatedCircle> drawable(new uirenderer::skiapipeline::AnimatedCircle(x, y, radius, paint));
758 mCanvas->drawDrawable(drawable.get());
759 }
760
761 // ----------------------------------------------------------------------------
762 // Canvas draw operations: View System
763 // ----------------------------------------------------------------------------
764
drawLayer(uirenderer::DeferredLayerUpdater * layerUpdater)765 void SkiaCanvas::drawLayer(uirenderer::DeferredLayerUpdater* layerUpdater) {
766 LOG_ALWAYS_FATAL("SkiaCanvas can't directly draw Layers");
767 }
768
drawRenderNode(uirenderer::RenderNode * renderNode)769 void SkiaCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) {
770 LOG_ALWAYS_FATAL("SkiaCanvas can't directly draw RenderNodes");
771 }
772
callDrawGLFunction(Functor * functor,uirenderer::GlFunctorLifecycleListener * listener)773 void SkiaCanvas::callDrawGLFunction(Functor* functor,
774 uirenderer::GlFunctorLifecycleListener* listener) {
775 LOG_ALWAYS_FATAL("SkiaCanvas can't directly draw GL Content");
776 }
777
778 } // namespace android
779