• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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->drawRect({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(const SkVertices * vertices,SkBlendMode mode,const SkPaint & paint)524 void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
525     mCanvas->drawVertices(vertices, mode, paint);
526 }
527 
528 // ----------------------------------------------------------------------------
529 // Canvas draw operations: Bitmaps
530 // ----------------------------------------------------------------------------
531 
drawBitmap(Bitmap & bitmap,float left,float top,const SkPaint * paint)532 void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
533     mCanvas->drawImage(bitmap.makeImage(), left, top, paint);
534 }
535 
drawBitmap(Bitmap & hwuiBitmap,const SkMatrix & matrix,const SkPaint * paint)536 void SkiaCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix, const SkPaint* paint) {
537     SkAutoCanvasRestore acr(mCanvas, true);
538     mCanvas->concat(matrix);
539     mCanvas->drawImage(hwuiBitmap.makeImage(), 0, 0, paint);
540 }
541 
drawBitmap(Bitmap & hwuiBitmap,float srcLeft,float srcTop,float srcRight,float srcBottom,float dstLeft,float dstTop,float dstRight,float dstBottom,const SkPaint * paint)542 void SkiaCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float srcTop,
543                             float srcRight, float srcBottom, float dstLeft, float dstTop,
544                             float dstRight, float dstBottom, const SkPaint* paint) {
545     SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
546     SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
547     mCanvas->drawImageRect(hwuiBitmap.makeImage(), srcRect, dstRect, paint);
548 }
549 
drawBitmapMesh(Bitmap & hwuiBitmap,int meshWidth,int meshHeight,const float * vertices,const int * colors,const SkPaint * paint)550 void SkiaCanvas::drawBitmapMesh(Bitmap& hwuiBitmap, int meshWidth, int meshHeight,
551         const float* vertices, const int* colors, const SkPaint* paint) {
552     const int ptCount = (meshWidth + 1) * (meshHeight + 1);
553     const int indexCount = meshWidth * meshHeight * 6;
554     uint32_t flags = SkVertices::kHasTexCoords_BuilderFlag;
555     if (colors) {
556         flags |= SkVertices::kHasColors_BuilderFlag;
557     }
558     SkVertices::Builder builder(SkVertices::kTriangles_VertexMode, ptCount, indexCount, flags);
559     memcpy(builder.positions(), vertices, ptCount * sizeof(SkPoint));
560     if (colors) {
561         memcpy(builder.colors(), colors, ptCount * sizeof(SkColor));
562     }
563     SkPoint* texs = builder.texCoords();
564     uint16_t* indices = builder.indices();
565 
566     // cons up texture coordinates and indices
567     {
568         const SkScalar w = SkIntToScalar(hwuiBitmap.width());
569         const SkScalar h = SkIntToScalar(hwuiBitmap.height());
570         const SkScalar dx = w / meshWidth;
571         const SkScalar dy = h / meshHeight;
572 
573         SkPoint* texsPtr = texs;
574         SkScalar y = 0;
575         for (int i = 0; i <= meshHeight; i++) {
576             if (i == meshHeight) {
577                 y = h;  // to ensure numerically we hit h exactly
578             }
579             SkScalar x = 0;
580             for (int j = 0; j < meshWidth; j++) {
581                 texsPtr->set(x, y);
582                 texsPtr += 1;
583                 x += dx;
584             }
585             texsPtr->set(w, y);
586             texsPtr += 1;
587             y += dy;
588         }
589         SkASSERT(texsPtr - texs == ptCount);
590     }
591 
592     // cons up indices
593     {
594         uint16_t* indexPtr = indices;
595         int index = 0;
596         for (int i = 0; i < meshHeight; i++) {
597             for (int j = 0; j < meshWidth; j++) {
598                 // lower-left triangle
599                 *indexPtr++ = index;
600                 *indexPtr++ = index + meshWidth + 1;
601                 *indexPtr++ = index + meshWidth + 2;
602                 // upper-right triangle
603                 *indexPtr++ = index;
604                 *indexPtr++ = index + meshWidth + 2;
605                 *indexPtr++ = index + 1;
606                 // bump to the next cell
607                 index += 1;
608             }
609             // bump to the next row
610             index += 1;
611         }
612         SkASSERT(indexPtr - indices == indexCount);
613     }
614 
615     // double-check that we have legal indices
616 #ifdef SK_DEBUG
617     {
618         for (int i = 0; i < indexCount; i++) {
619             SkASSERT((unsigned)indices[i] < (unsigned)ptCount);
620         }
621     }
622 #endif
623 
624     // cons-up a shader for the bitmap
625     SkPaint tmpPaint;
626     if (paint) {
627         tmpPaint = *paint;
628     }
629 
630     sk_sp<SkImage> image = hwuiBitmap.makeImage();
631     tmpPaint.setShader(image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode));
632 
633     mCanvas->drawVertices(builder.detach(), SkBlendMode::kModulate, tmpPaint);
634 }
635 
drawNinePatch(Bitmap & hwuiBitmap,const Res_png_9patch & chunk,float dstLeft,float dstTop,float dstRight,float dstBottom,const SkPaint * paint)636 void SkiaCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk,
637         float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {
638 
639     SkCanvas::Lattice lattice;
640     NinePatchUtils::SetLatticeDivs(&lattice, chunk, hwuiBitmap.width(), hwuiBitmap.height());
641 
642     lattice.fFlags = nullptr;
643     int numFlags = 0;
644     if (chunk.numColors > 0 && chunk.numColors == NinePatchUtils::NumDistinctRects(lattice)) {
645         // We can expect the framework to give us a color for every distinct rect.
646         // Skia requires a flag for every rect.
647         numFlags = (lattice.fXCount + 1) * (lattice.fYCount + 1);
648     }
649 
650     SkAutoSTMalloc<25, SkCanvas::Lattice::Flags> flags(numFlags);
651     if (numFlags > 0) {
652         NinePatchUtils::SetLatticeFlags(&lattice, flags.get(), numFlags, chunk);
653     }
654 
655     lattice.fBounds = nullptr;
656     SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
657     mCanvas->drawImageLattice(hwuiBitmap.makeImage().get(), lattice, dst, paint);
658 }
659 
drawVectorDrawable(VectorDrawableRoot * vectorDrawable)660 void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) {
661     vectorDrawable->drawStaging(this);
662 }
663 
664 // ----------------------------------------------------------------------------
665 // Canvas draw operations: Text
666 // ----------------------------------------------------------------------------
667 
drawGlyphs(ReadGlyphFunc glyphFunc,int count,const SkPaint & paint,float x,float y,float boundsLeft,float boundsTop,float boundsRight,float boundsBottom,float totalAdvance)668 void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& paint, float x,
669         float y, float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
670         float totalAdvance) {
671     if (count <= 0 || paint.nothingToDraw()) return;
672     // Set align to left for drawing, as we don't want individual
673     // glyphs centered or right-aligned; the offset above takes
674     // care of all alignment.
675     SkPaint paintCopy(paint);
676     paintCopy.setTextAlign(SkPaint::kLeft_Align);
677 
678     SkRect bounds = SkRect::MakeLTRB(boundsLeft + x, boundsTop + y,
679                                      boundsRight + x, boundsBottom + y);
680 
681     SkTextBlobBuilder builder;
682     const SkTextBlobBuilder::RunBuffer& buffer = builder.allocRunPos(paintCopy, count, &bounds);
683     glyphFunc(buffer.glyphs, buffer.pos);
684 
685     sk_sp<SkTextBlob> textBlob(builder.make());
686     mCanvas->drawTextBlob(textBlob, 0, 0, paintCopy);
687     drawTextDecorations(x, y, totalAdvance, paintCopy);
688 }
689 
drawLayoutOnPath(const minikin::Layout & layout,float hOffset,float vOffset,const SkPaint & paint,const SkPath & path,size_t start,size_t end)690 void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
691         const SkPaint& paint, const SkPath& path, size_t start, size_t end) {
692     const int N = end - start;
693     SkAutoSTMalloc<1024, uint8_t> storage(N * (sizeof(uint16_t) + sizeof(SkRSXform)));
694     SkRSXform* xform = (SkRSXform*)storage.get();
695     uint16_t* glyphs = (uint16_t*)(xform + N);
696     SkPathMeasure meas(path, false);
697 
698     for (size_t i = start; i < end; i++) {
699         glyphs[i - start] = layout.getGlyphId(i);
700         float x = hOffset + layout.getX(i);
701         float y = vOffset + layout.getY(i);
702 
703         SkPoint pos;
704         SkVector tan;
705         if (!meas.getPosTan(x, &pos, &tan)) {
706             pos.set(x, y);
707             tan.set(1, 0);
708         }
709         xform[i - start].fSCos = tan.x();
710         xform[i - start].fSSin = tan.y();
711         xform[i - start].fTx   = pos.x() - tan.y() * y;
712         xform[i - start].fTy   = pos.y() + tan.x() * y;
713     }
714 
715     this->asSkCanvas()->drawTextRSXform(glyphs, sizeof(uint16_t) * N, xform, nullptr, paint);
716 }
717 
718 // ----------------------------------------------------------------------------
719 // Canvas draw operations: Animations
720 // ----------------------------------------------------------------------------
721 
drawRoundRect(uirenderer::CanvasPropertyPrimitive * left,uirenderer::CanvasPropertyPrimitive * top,uirenderer::CanvasPropertyPrimitive * right,uirenderer::CanvasPropertyPrimitive * bottom,uirenderer::CanvasPropertyPrimitive * rx,uirenderer::CanvasPropertyPrimitive * ry,uirenderer::CanvasPropertyPaint * paint)722 void SkiaCanvas::drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
723         uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
724         uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
725         uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) {
726     sk_sp<uirenderer::skiapipeline::AnimatedRoundRect> drawable(
727             new uirenderer::skiapipeline::AnimatedRoundRect(left, top, right, bottom, rx, ry, paint));
728     mCanvas->drawDrawable(drawable.get());
729 }
730 
drawCircle(uirenderer::CanvasPropertyPrimitive * x,uirenderer::CanvasPropertyPrimitive * y,uirenderer::CanvasPropertyPrimitive * radius,uirenderer::CanvasPropertyPaint * paint)731 void SkiaCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x, uirenderer::CanvasPropertyPrimitive* y,
732         uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPaint* paint) {
733     sk_sp<uirenderer::skiapipeline::AnimatedCircle> drawable(new uirenderer::skiapipeline::AnimatedCircle(x, y, radius, paint));
734     mCanvas->drawDrawable(drawable.get());
735 }
736 
737 // ----------------------------------------------------------------------------
738 // Canvas draw operations: View System
739 // ----------------------------------------------------------------------------
740 
drawLayer(uirenderer::DeferredLayerUpdater * layerUpdater)741 void SkiaCanvas::drawLayer(uirenderer::DeferredLayerUpdater* layerUpdater) {
742     LOG_ALWAYS_FATAL("SkiaCanvas can't directly draw Layers");
743 }
744 
drawRenderNode(uirenderer::RenderNode * renderNode)745 void SkiaCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) {
746     LOG_ALWAYS_FATAL("SkiaCanvas can't directly draw RenderNodes");
747 }
748 
callDrawGLFunction(Functor * functor,uirenderer::GlFunctorLifecycleListener * listener)749 void SkiaCanvas::callDrawGLFunction(Functor* functor,
750         uirenderer::GlFunctorLifecycleListener* listener) {
751     LOG_ALWAYS_FATAL("SkiaCanvas can't directly draw GL Content");
752 }
753 
754 } // namespace android
755