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