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