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