SkiaCanvas.cpp revision edca320a2b42011f98c308fdf25fc0494c6a5454
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 "Canvas.h" 18 19#include <SkCanvas.h> 20#include <SkClipStack.h> 21#include <SkDevice.h> 22#include <SkDeque.h> 23#include <SkDrawFilter.h> 24#include <SkGraphics.h> 25#include <SkShader.h> 26#include <SkTArray.h> 27#include <SkTemplates.h> 28 29#include <memory> 30 31namespace android { 32 33// Holds an SkCanvas reference plus additional native data. 34class SkiaCanvas : public Canvas { 35public: 36 explicit SkiaCanvas(const SkBitmap& bitmap); 37 38 /** 39 * Create a new SkiaCanvas. 40 * 41 * @param canvas SkCanvas to handle calls made to this SkiaCanvas. Must 42 * not be NULL. This constructor will ref() the SkCanvas, and unref() 43 * it in its destructor. 44 */ 45 explicit SkiaCanvas(SkCanvas* canvas) : mCanvas(canvas) { 46 SkASSERT(canvas); 47 canvas->ref(); 48 } 49 50 virtual SkCanvas* asSkCanvas() override { 51 return mCanvas.get(); 52 } 53 54 virtual void setBitmap(const SkBitmap& bitmap) override; 55 56 virtual bool isOpaque() override; 57 virtual int width() override; 58 virtual int height() override; 59 60 virtual void setHighContrastText(bool highContrastText) override { 61 mHighContrastText = highContrastText; 62 } 63 virtual bool isHighContrastText() override { return mHighContrastText; } 64 65 virtual int getSaveCount() const override; 66 virtual int save(SkCanvas::SaveFlags flags) override; 67 virtual void restore() override; 68 virtual void restoreToCount(int saveCount) override; 69 70 virtual int saveLayer(float left, float top, float right, float bottom, 71 const SkPaint* paint, SkCanvas::SaveFlags flags) override; 72 virtual int saveLayerAlpha(float left, float top, float right, float bottom, 73 int alpha, SkCanvas::SaveFlags flags) override; 74 75 virtual void getMatrix(SkMatrix* outMatrix) const override; 76 virtual void setMatrix(const SkMatrix& matrix) override; 77 virtual void setLocalMatrix(const SkMatrix& matrix) override { this->setMatrix(matrix); } 78 virtual void concat(const SkMatrix& matrix) override; 79 virtual void rotate(float degrees) override; 80 virtual void scale(float sx, float sy) override; 81 virtual void skew(float sx, float sy) override; 82 virtual void translate(float dx, float dy) override; 83 84 virtual bool getClipBounds(SkRect* outRect) const override; 85 virtual bool quickRejectRect(float left, float top, float right, float bottom) const override; 86 virtual bool quickRejectPath(const SkPath& path) const override; 87 virtual bool clipRect(float left, float top, float right, float bottom, 88 SkRegion::Op op) override; 89 virtual bool clipPath(const SkPath* path, SkRegion::Op op) override; 90 virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) override; 91 92 virtual SkDrawFilter* getDrawFilter() override; 93 virtual void setDrawFilter(SkDrawFilter* drawFilter) override; 94 95 virtual void drawColor(int color, SkXfermode::Mode mode) override; 96 virtual void drawPaint(const SkPaint& paint) override; 97 98 virtual void drawPoint(float x, float y, const SkPaint& paint) override; 99 virtual void drawPoints(const float* points, int count, const SkPaint& paint) override; 100 virtual void drawLine(float startX, float startY, float stopX, float stopY, 101 const SkPaint& paint) override; 102 virtual void drawLines(const float* points, int count, const SkPaint& paint) override; 103 virtual void drawRect(float left, float top, float right, float bottom, 104 const SkPaint& paint) override; 105 virtual void drawRegion(const SkRegion& region, const SkPaint& paint) override; 106 virtual void drawRoundRect(float left, float top, float right, float bottom, 107 float rx, float ry, const SkPaint& paint) override; 108 virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) override; 109 virtual void drawOval(float left, float top, float right, float bottom, 110 const SkPaint& paint) override; 111 virtual void drawArc(float left, float top, float right, float bottom, 112 float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) override; 113 virtual void drawPath(const SkPath& path, const SkPaint& paint) override; 114 virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount, 115 const float* verts, const float* tex, const int* colors, 116 const uint16_t* indices, int indexCount, const SkPaint& paint) override; 117 118 virtual void drawBitmap(const SkBitmap& bitmap, float left, float top, 119 const SkPaint* paint) override; 120 virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, 121 const SkPaint* paint) override; 122 virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop, 123 float srcRight, float srcBottom, float dstLeft, float dstTop, 124 float dstRight, float dstBottom, const SkPaint* paint) override; 125 virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight, 126 const float* vertices, const int* colors, const SkPaint* paint) override; 127 virtual void drawNinePatch(const SkBitmap& bitmap, const android::Res_png_9patch& chunk, 128 float dstLeft, float dstTop, float dstRight, float dstBottom, 129 const SkPaint* paint) override; 130 131 virtual void drawText(const uint16_t* text, const float* positions, int count, 132 const SkPaint& paint, float x, float y, 133 float boundsLeft, float boundsTop, float boundsRight, float boundsBottom, 134 float totalAdvance) override; 135 virtual void drawPosText(const uint16_t* text, const float* positions, int count, 136 int posCount, const SkPaint& paint) override; 137 virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path, 138 float hOffset, float vOffset, const SkPaint& paint) override; 139 140 virtual bool drawTextAbsolutePos() const override { return true; } 141 142private: 143 struct SaveRec { 144 int saveCount; 145 SkCanvas::SaveFlags saveFlags; 146 }; 147 148 bool mHighContrastText = false; 149 150 void recordPartialSave(SkCanvas::SaveFlags flags); 151 void saveClipsForFrame(SkTArray<SkClipStack::Element>& clips, int frameSaveCount); 152 void applyClips(const SkTArray<SkClipStack::Element>& clips); 153 154 void drawPoints(const float* points, int count, const SkPaint& paint, 155 SkCanvas::PointMode mode); 156 void drawTextDecorations(float x, float y, float length, const SkPaint& paint); 157 158 SkAutoTUnref<SkCanvas> mCanvas; 159 std::unique_ptr<SkDeque> mSaveStack; // lazily allocated, tracks partial saves. 160}; 161 162Canvas* Canvas::create_canvas(const SkBitmap& bitmap) { 163 return new SkiaCanvas(bitmap); 164} 165 166Canvas* Canvas::create_canvas(SkCanvas* skiaCanvas) { 167 return new SkiaCanvas(skiaCanvas); 168} 169 170SkiaCanvas::SkiaCanvas(const SkBitmap& bitmap) { 171 mCanvas.reset(new SkCanvas(bitmap)); 172} 173 174// ---------------------------------------------------------------------------- 175// Canvas state operations: Replace Bitmap 176// ---------------------------------------------------------------------------- 177 178class ClipCopier : public SkCanvas::ClipVisitor { 179public: 180 ClipCopier(SkCanvas* dstCanvas) : m_dstCanvas(dstCanvas) {} 181 182 virtual void clipRect(const SkRect& rect, SkRegion::Op op, bool antialias) { 183 m_dstCanvas->clipRect(rect, op, antialias); 184 } 185 virtual void clipRRect(const SkRRect& rrect, SkRegion::Op op, bool antialias) { 186 m_dstCanvas->clipRRect(rrect, op, antialias); 187 } 188 virtual void clipPath(const SkPath& path, SkRegion::Op op, bool antialias) { 189 m_dstCanvas->clipPath(path, op, antialias); 190 } 191 192private: 193 SkCanvas* m_dstCanvas; 194}; 195 196void SkiaCanvas::setBitmap(const SkBitmap& bitmap) { 197 SkCanvas* newCanvas = new SkCanvas(bitmap); 198 SkASSERT(newCanvas); 199 200 if (!bitmap.isNull()) { 201 // Copy the canvas matrix & clip state. 202 newCanvas->setMatrix(mCanvas->getTotalMatrix()); 203 if (NULL != mCanvas->getDevice() && NULL != newCanvas->getDevice()) { 204 ClipCopier copier(newCanvas); 205 mCanvas->replayClips(&copier); 206 } 207 } 208 209 // unrefs the existing canvas 210 mCanvas.reset(newCanvas); 211 212 // clean up the old save stack 213 mSaveStack.reset(NULL); 214} 215 216// ---------------------------------------------------------------------------- 217// Canvas state operations 218// ---------------------------------------------------------------------------- 219 220bool SkiaCanvas::isOpaque() { 221 return mCanvas->getDevice()->accessBitmap(false).isOpaque(); 222} 223 224int SkiaCanvas::width() { 225 return mCanvas->getBaseLayerSize().width(); 226} 227 228int SkiaCanvas::height() { 229 return mCanvas->getBaseLayerSize().height(); 230} 231 232// ---------------------------------------------------------------------------- 233// Canvas state operations: Save (layer) 234// ---------------------------------------------------------------------------- 235 236int SkiaCanvas::getSaveCount() const { 237 return mCanvas->getSaveCount(); 238} 239 240int SkiaCanvas::save(SkCanvas::SaveFlags flags) { 241 int count = mCanvas->save(); 242 recordPartialSave(flags); 243 return count; 244} 245 246void SkiaCanvas::restore() { 247 const SaveRec* rec = (NULL == mSaveStack.get()) 248 ? NULL 249 : static_cast<SaveRec*>(mSaveStack->back()); 250 int currentSaveCount = mCanvas->getSaveCount() - 1; 251 SkASSERT(NULL == rec || currentSaveCount >= rec->saveCount); 252 253 if (NULL == rec || rec->saveCount != currentSaveCount) { 254 // Fast path - no record for this frame. 255 mCanvas->restore(); 256 return; 257 } 258 259 bool preserveMatrix = !(rec->saveFlags & SkCanvas::kMatrix_SaveFlag); 260 bool preserveClip = !(rec->saveFlags & SkCanvas::kClip_SaveFlag); 261 262 SkMatrix savedMatrix; 263 if (preserveMatrix) { 264 savedMatrix = mCanvas->getTotalMatrix(); 265 } 266 267 SkTArray<SkClipStack::Element> savedClips; 268 if (preserveClip) { 269 saveClipsForFrame(savedClips, currentSaveCount); 270 } 271 272 mCanvas->restore(); 273 274 if (preserveMatrix) { 275 mCanvas->setMatrix(savedMatrix); 276 } 277 278 if (preserveClip && !savedClips.empty()) { 279 applyClips(savedClips); 280 } 281 282 mSaveStack->pop_back(); 283} 284 285void SkiaCanvas::restoreToCount(int restoreCount) { 286 while (mCanvas->getSaveCount() > restoreCount) { 287 this->restore(); 288 } 289} 290 291int SkiaCanvas::saveLayer(float left, float top, float right, float bottom, 292 const SkPaint* paint, SkCanvas::SaveFlags flags) { 293 SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom); 294 int count = mCanvas->saveLayer(&bounds, paint, flags | SkCanvas::kMatrixClip_SaveFlag); 295 recordPartialSave(flags); 296 return count; 297} 298 299int SkiaCanvas::saveLayerAlpha(float left, float top, float right, float bottom, 300 int alpha, SkCanvas::SaveFlags flags) { 301 SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom); 302 int count = mCanvas->saveLayerAlpha(&bounds, alpha, flags | SkCanvas::kMatrixClip_SaveFlag); 303 recordPartialSave(flags); 304 return count; 305} 306 307// ---------------------------------------------------------------------------- 308// functions to emulate legacy SaveFlags (i.e. independent matrix/clip flags) 309// ---------------------------------------------------------------------------- 310 311void SkiaCanvas::recordPartialSave(SkCanvas::SaveFlags flags) { 312 // A partial save is a save operation which doesn't capture the full canvas state. 313 // (either kMatrix_SaveFlags or kClip_SaveFlag is missing). 314 315 // Mask-out non canvas state bits. 316 flags = static_cast<SkCanvas::SaveFlags>(flags & SkCanvas::kMatrixClip_SaveFlag); 317 318 if (SkCanvas::kMatrixClip_SaveFlag == flags) { 319 // not a partial save. 320 return; 321 } 322 323 if (NULL == mSaveStack.get()) { 324 mSaveStack.reset(SkNEW_ARGS(SkDeque, (sizeof(struct SaveRec), 8))); 325 } 326 327 SaveRec* rec = static_cast<SaveRec*>(mSaveStack->push_back()); 328 // Store the save counter in the SkClipStack domain. 329 // (0-based, equal to the number of save ops on the stack). 330 rec->saveCount = mCanvas->getSaveCount() - 1; 331 rec->saveFlags = flags; 332} 333 334void SkiaCanvas::saveClipsForFrame(SkTArray<SkClipStack::Element>& clips, int frameSaveCount) { 335 SkClipStack::Iter clipIterator(*mCanvas->getClipStack(), 336 SkClipStack::Iter::kTop_IterStart); 337 while (const SkClipStack::Element* elem = clipIterator.next()) { 338 if (elem->getSaveCount() < frameSaveCount) { 339 // done with the current frame. 340 break; 341 } 342 SkASSERT(elem->getSaveCount() == frameSaveCount); 343 clips.push_back(*elem); 344 } 345} 346 347void SkiaCanvas::applyClips(const SkTArray<SkClipStack::Element>& clips) { 348 ClipCopier clipCopier(mCanvas); 349 350 // The clip stack stores clips in device space. 351 SkMatrix origMatrix = mCanvas->getTotalMatrix(); 352 mCanvas->resetMatrix(); 353 354 // We pushed the clips in reverse order. 355 for (int i = clips.count() - 1; i >= 0; --i) { 356 clips[i].replay(&clipCopier); 357 } 358 359 mCanvas->setMatrix(origMatrix); 360} 361 362// ---------------------------------------------------------------------------- 363// Canvas state operations: Matrix 364// ---------------------------------------------------------------------------- 365 366void SkiaCanvas::getMatrix(SkMatrix* outMatrix) const { 367 *outMatrix = mCanvas->getTotalMatrix(); 368} 369 370void SkiaCanvas::setMatrix(const SkMatrix& matrix) { 371 mCanvas->setMatrix(matrix); 372} 373 374void SkiaCanvas::concat(const SkMatrix& matrix) { 375 mCanvas->concat(matrix); 376} 377 378void SkiaCanvas::rotate(float degrees) { 379 mCanvas->rotate(degrees); 380} 381 382void SkiaCanvas::scale(float sx, float sy) { 383 mCanvas->scale(sx, sy); 384} 385 386void SkiaCanvas::skew(float sx, float sy) { 387 mCanvas->skew(sx, sy); 388} 389 390void SkiaCanvas::translate(float dx, float dy) { 391 mCanvas->translate(dx, dy); 392} 393 394// ---------------------------------------------------------------------------- 395// Canvas state operations: Clips 396// ---------------------------------------------------------------------------- 397 398// This function is a mirror of SkCanvas::getClipBounds except that it does 399// not outset the edge of the clip to account for anti-aliasing. There is 400// a skia bug to investigate pushing this logic into back into skia. 401// (see https://code.google.com/p/skia/issues/detail?id=1303) 402bool SkiaCanvas::getClipBounds(SkRect* outRect) const { 403 SkIRect ibounds; 404 if (!mCanvas->getClipDeviceBounds(&ibounds)) { 405 return false; 406 } 407 408 SkMatrix inverse; 409 // if we can't invert the CTM, we can't return local clip bounds 410 if (!mCanvas->getTotalMatrix().invert(&inverse)) { 411 if (outRect) { 412 outRect->setEmpty(); 413 } 414 return false; 415 } 416 417 if (NULL != outRect) { 418 SkRect r = SkRect::Make(ibounds); 419 inverse.mapRect(outRect, r); 420 } 421 return true; 422} 423 424bool SkiaCanvas::quickRejectRect(float left, float top, float right, float bottom) const { 425 SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom); 426 return mCanvas->quickReject(bounds); 427} 428 429bool SkiaCanvas::quickRejectPath(const SkPath& path) const { 430 return mCanvas->quickReject(path); 431} 432 433bool SkiaCanvas::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { 434 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); 435 mCanvas->clipRect(rect, op); 436 return !mCanvas->isClipEmpty(); 437} 438 439bool SkiaCanvas::clipPath(const SkPath* path, SkRegion::Op op) { 440 mCanvas->clipPath(*path, op); 441 return !mCanvas->isClipEmpty(); 442} 443 444bool SkiaCanvas::clipRegion(const SkRegion* region, SkRegion::Op op) { 445 SkPath rgnPath; 446 if (region->getBoundaryPath(&rgnPath)) { 447 // The region is specified in device space. 448 SkMatrix savedMatrix = mCanvas->getTotalMatrix(); 449 mCanvas->resetMatrix(); 450 mCanvas->clipPath(rgnPath, op); 451 mCanvas->setMatrix(savedMatrix); 452 } else { 453 mCanvas->clipRect(SkRect::MakeEmpty(), op); 454 } 455 return !mCanvas->isClipEmpty(); 456} 457 458// ---------------------------------------------------------------------------- 459// Canvas state operations: Filters 460// ---------------------------------------------------------------------------- 461 462SkDrawFilter* SkiaCanvas::getDrawFilter() { 463 return mCanvas->getDrawFilter(); 464} 465 466void SkiaCanvas::setDrawFilter(SkDrawFilter* drawFilter) { 467 mCanvas->setDrawFilter(drawFilter); 468} 469 470// ---------------------------------------------------------------------------- 471// Canvas draw operations 472// ---------------------------------------------------------------------------- 473 474void SkiaCanvas::drawColor(int color, SkXfermode::Mode mode) { 475 mCanvas->drawColor(color, mode); 476} 477 478void SkiaCanvas::drawPaint(const SkPaint& paint) { 479 mCanvas->drawPaint(paint); 480} 481 482// ---------------------------------------------------------------------------- 483// Canvas draw operations: Geometry 484// ---------------------------------------------------------------------------- 485 486void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint, 487 SkCanvas::PointMode mode) { 488 // convert the floats into SkPoints 489 count >>= 1; // now it is the number of points 490 SkAutoSTMalloc<32, SkPoint> storage(count); 491 SkPoint* pts = storage.get(); 492 for (int i = 0; i < count; i++) { 493 pts[i].set(points[0], points[1]); 494 points += 2; 495 } 496 mCanvas->drawPoints(mode, count, pts, paint); 497} 498 499 500void SkiaCanvas::drawPoint(float x, float y, const SkPaint& paint) { 501 mCanvas->drawPoint(x, y, paint); 502} 503 504void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint) { 505 this->drawPoints(points, count, paint, SkCanvas::kPoints_PointMode); 506} 507 508void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY, 509 const SkPaint& paint) { 510 mCanvas->drawLine(startX, startY, stopX, stopY, paint); 511} 512 513void SkiaCanvas::drawLines(const float* points, int count, const SkPaint& paint) { 514 this->drawPoints(points, count, paint, SkCanvas::kLines_PointMode); 515} 516 517void SkiaCanvas::drawRect(float left, float top, float right, float bottom, 518 const SkPaint& paint) { 519 mCanvas->drawRectCoords(left, top, right, bottom, paint); 520 521} 522 523void SkiaCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) { 524 SkRegion::Iterator it(region); 525 while (!it.done()) { 526 mCanvas->drawRect(SkRect::Make(it.rect()), paint); 527 it.next(); 528 } 529} 530 531void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom, 532 float rx, float ry, const SkPaint& paint) { 533 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); 534 mCanvas->drawRoundRect(rect, rx, ry, paint); 535} 536 537void SkiaCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) { 538 mCanvas->drawCircle(x, y, radius, paint); 539} 540 541void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) { 542 SkRect oval = SkRect::MakeLTRB(left, top, right, bottom); 543 mCanvas->drawOval(oval, paint); 544} 545 546void SkiaCanvas::drawArc(float left, float top, float right, float bottom, 547 float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) { 548 SkRect arc = SkRect::MakeLTRB(left, top, right, bottom); 549 mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, paint); 550} 551 552void SkiaCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 553 mCanvas->drawPath(path, paint); 554} 555 556void SkiaCanvas::drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount, 557 const float* verts, const float* texs, const int* colors, 558 const uint16_t* indices, int indexCount, const SkPaint& paint) { 559#ifndef SK_SCALAR_IS_FLOAT 560 SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid"); 561#endif 562 const int ptCount = vertexCount >> 1; 563 mCanvas->drawVertices(vertexMode, ptCount, (SkPoint*)verts, (SkPoint*)texs, 564 (SkColor*)colors, NULL, indices, indexCount, paint); 565} 566 567// ---------------------------------------------------------------------------- 568// Canvas draw operations: Bitmaps 569// ---------------------------------------------------------------------------- 570 571void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint) { 572 mCanvas->drawBitmap(bitmap, left, top, paint); 573} 574 575void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) { 576 SkAutoCanvasRestore acr(mCanvas, true); 577 mCanvas->concat(matrix); 578 mCanvas->drawBitmap(bitmap, 0, 0, paint); 579} 580 581void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop, 582 float srcRight, float srcBottom, float dstLeft, float dstTop, 583 float dstRight, float dstBottom, const SkPaint* paint) { 584 SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom); 585 SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); 586 mCanvas->drawBitmapRectToRect(bitmap, &srcRect, dstRect, paint); 587} 588 589void SkiaCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight, 590 const float* vertices, const int* colors, const SkPaint* paint) { 591 592 const int ptCount = (meshWidth + 1) * (meshHeight + 1); 593 const int indexCount = meshWidth * meshHeight * 6; 594 595 /* Our temp storage holds 2 or 3 arrays. 596 texture points [ptCount * sizeof(SkPoint)] 597 optionally vertex points [ptCount * sizeof(SkPoint)] if we need a 598 copy to convert from float to fixed 599 indices [ptCount * sizeof(uint16_t)] 600 */ 601 ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[] 602 storageSize += indexCount * sizeof(uint16_t); // indices[] 603 604 605#ifndef SK_SCALAR_IS_FLOAT 606 SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid"); 607#endif 608 SkAutoMalloc storage(storageSize); 609 SkPoint* texs = (SkPoint*)storage.get(); 610 uint16_t* indices = (uint16_t*)(texs + ptCount); 611 612 // cons up texture coordinates and indices 613 { 614 const SkScalar w = SkIntToScalar(bitmap.width()); 615 const SkScalar h = SkIntToScalar(bitmap.height()); 616 const SkScalar dx = w / meshWidth; 617 const SkScalar dy = h / meshHeight; 618 619 SkPoint* texsPtr = texs; 620 SkScalar y = 0; 621 for (int i = 0; i <= meshHeight; i++) { 622 if (i == meshHeight) { 623 y = h; // to ensure numerically we hit h exactly 624 } 625 SkScalar x = 0; 626 for (int j = 0; j < meshWidth; j++) { 627 texsPtr->set(x, y); 628 texsPtr += 1; 629 x += dx; 630 } 631 texsPtr->set(w, y); 632 texsPtr += 1; 633 y += dy; 634 } 635 SkASSERT(texsPtr - texs == ptCount); 636 } 637 638 // cons up indices 639 { 640 uint16_t* indexPtr = indices; 641 int index = 0; 642 for (int i = 0; i < meshHeight; i++) { 643 for (int j = 0; j < meshWidth; j++) { 644 // lower-left triangle 645 *indexPtr++ = index; 646 *indexPtr++ = index + meshWidth + 1; 647 *indexPtr++ = index + meshWidth + 2; 648 // upper-right triangle 649 *indexPtr++ = index; 650 *indexPtr++ = index + meshWidth + 2; 651 *indexPtr++ = index + 1; 652 // bump to the next cell 653 index += 1; 654 } 655 // bump to the next row 656 index += 1; 657 } 658 SkASSERT(indexPtr - indices == indexCount); 659 SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize); 660 } 661 662 // double-check that we have legal indices 663#ifdef SK_DEBUG 664 { 665 for (int i = 0; i < indexCount; i++) { 666 SkASSERT((unsigned)indices[i] < (unsigned)ptCount); 667 } 668 } 669#endif 670 671 // cons-up a shader for the bitmap 672 SkPaint tmpPaint; 673 if (paint) { 674 tmpPaint = *paint; 675 } 676 SkShader* shader = SkShader::CreateBitmapShader(bitmap, 677 SkShader::kClamp_TileMode, 678 SkShader::kClamp_TileMode); 679 SkSafeUnref(tmpPaint.setShader(shader)); 680 681 mCanvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, (SkPoint*)vertices, 682 texs, (const SkColor*)colors, NULL, indices, 683 indexCount, tmpPaint); 684} 685 686void SkiaCanvas::drawNinePatch(const SkBitmap& bitmap, const Res_png_9patch& chunk, 687 float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) { 688 SkRect bounds = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); 689 NinePatch::Draw(mCanvas, bounds, bitmap, chunk, paint, nullptr); 690} 691 692// ---------------------------------------------------------------------------- 693// Canvas draw operations: Text 694// ---------------------------------------------------------------------------- 695 696void SkiaCanvas::drawText(const uint16_t* text, const float* positions, int count, 697 const SkPaint& paint, float x, float y, 698 float boundsLeft, float boundsTop, float boundsRight, float boundsBottom, 699 float totalAdvance) { 700 // Set align to left for drawing, as we don't want individual 701 // glyphs centered or right-aligned; the offset above takes 702 // care of all alignment. 703 SkPaint paintCopy(paint); 704 paintCopy.setTextAlign(SkPaint::kLeft_Align); 705 706 SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats); 707 mCanvas->drawPosText(text, count << 1, reinterpret_cast<const SkPoint*>(positions), paintCopy); 708} 709 710void SkiaCanvas::drawPosText(const uint16_t* text, const float* positions, int count, int posCount, 711 const SkPaint& paint) { 712 SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL; 713 int indx; 714 for (indx = 0; indx < posCount; indx++) { 715 posPtr[indx].fX = positions[indx << 1]; 716 posPtr[indx].fY = positions[(indx << 1) + 1]; 717 } 718 719 SkPaint paintCopy(paint); 720 paintCopy.setTextEncoding(SkPaint::kUTF16_TextEncoding); 721 mCanvas->drawPosText(text, count, posPtr, paintCopy); 722 723 delete[] posPtr; 724} 725 726void SkiaCanvas::drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path, 727 float hOffset, float vOffset, const SkPaint& paint) { 728 mCanvas->drawTextOnPathHV(glyphs, count << 1, path, hOffset, vOffset, paint); 729} 730 731} // namespace android 732