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