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