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