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