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