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