1/* 2 Copyright 2011 Google Inc. 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 18#include "SkCanvas.h" 19#include "SkDevice.h" 20#include "SkPaint.h" 21#include "SkGPipe.h" 22#include "SkGPipePriv.h" 23#include "SkStream.h" 24#include "SkTSearch.h" 25#include "SkTypeface.h" 26#include "SkWriter32.h" 27#include "SkColorFilter.h" 28#include "SkDrawLooper.h" 29#include "SkMaskFilter.h" 30#include "SkRasterizer.h" 31#include "SkShader.h" 32 33static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) { 34 SkASSERT(paintFlat < kCount_PaintFlats); 35 switch (paintFlat) { 36 case kColorFilter_PaintFlat: return paint.getColorFilter(); 37 case kDrawLooper_PaintFlat: return paint.getLooper(); 38 case kMaskFilter_PaintFlat: return paint.getMaskFilter(); 39 case kPathEffect_PaintFlat: return paint.getPathEffect(); 40 case kRasterizer_PaintFlat: return paint.getRasterizer(); 41 case kShader_PaintFlat: return paint.getShader(); 42 case kXfermode_PaintFlat: return paint.getXfermode(); 43 } 44 SkASSERT(!"never gets here"); 45 return NULL; 46} 47 48static size_t estimateFlattenSize(const SkPath& path) { 49 int n = path.countPoints(); 50 size_t bytes = 3 * sizeof(int32_t); 51 bytes += n * sizeof(SkPoint); 52 bytes += SkAlign4(n + 2); // verbs: add 2 for move/close extras 53 54#ifdef SK_DEBUG 55 { 56 SkWriter32 writer(1024); 57 path.flatten(writer); 58 SkASSERT(writer.size() <= bytes); 59 } 60#endif 61 return bytes; 62} 63 64static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) { 65 SkASSERT(typeface); 66 SkDynamicMemoryWStream stream; 67 typeface->serialize(&stream); 68 size_t size = stream.getOffset(); 69 if (writer) { 70 writer->write32(size); 71 writer->write(stream.getStream(), size); 72 } 73 return 4 + size; 74} 75 76/////////////////////////////////////////////////////////////////////////////// 77 78class SkGPipeCanvas : public SkCanvas { 79public: 80 SkGPipeCanvas(SkGPipeController*, SkWriter32*, SkFactorySet*); 81 virtual ~SkGPipeCanvas(); 82 83 void finish() { 84 if (!fDone) { 85 this->writeOp(kDone_DrawOp); 86 this->doNotify(); 87 fDone = true; 88 } 89 } 90 91 // overrides from SkCanvas 92 virtual int save(SaveFlags); 93 virtual int saveLayer(const SkRect* bounds, const SkPaint*, SaveFlags); 94 virtual void restore(); 95 virtual bool translate(SkScalar dx, SkScalar dy); 96 virtual bool scale(SkScalar sx, SkScalar sy); 97 virtual bool rotate(SkScalar degrees); 98 virtual bool skew(SkScalar sx, SkScalar sy); 99 virtual bool concat(const SkMatrix& matrix); 100 virtual void setMatrix(const SkMatrix& matrix); 101 virtual bool clipRect(const SkRect& rect, SkRegion::Op op); 102 virtual bool clipPath(const SkPath& path, SkRegion::Op op); 103 virtual bool clipRegion(const SkRegion& region, SkRegion::Op op); 104 virtual void clear(SkColor); 105 virtual void drawPaint(const SkPaint& paint); 106 virtual void drawPoints(PointMode, size_t count, const SkPoint pts[], 107 const SkPaint&); 108 virtual void drawRect(const SkRect& rect, const SkPaint&); 109 virtual void drawPath(const SkPath& path, const SkPaint&); 110 virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top, 111 const SkPaint*); 112 virtual void drawBitmapRect(const SkBitmap&, const SkIRect* src, 113 const SkRect& dst, const SkPaint*); 114 virtual void drawBitmapMatrix(const SkBitmap&, const SkMatrix&, 115 const SkPaint*); 116 virtual void drawSprite(const SkBitmap&, int left, int top, 117 const SkPaint*); 118 virtual void drawText(const void* text, size_t byteLength, SkScalar x, 119 SkScalar y, const SkPaint&); 120 virtual void drawPosText(const void* text, size_t byteLength, 121 const SkPoint pos[], const SkPaint&); 122 virtual void drawPosTextH(const void* text, size_t byteLength, 123 const SkScalar xpos[], SkScalar constY, const SkPaint&); 124 virtual void drawTextOnPath(const void* text, size_t byteLength, 125 const SkPath& path, const SkMatrix* matrix, 126 const SkPaint&); 127 virtual void drawPicture(SkPicture& picture); 128 virtual void drawShape(SkShape*); 129 virtual void drawVertices(VertexMode, int vertexCount, 130 const SkPoint vertices[], const SkPoint texs[], 131 const SkColor colors[], SkXfermode*, 132 const uint16_t indices[], int indexCount, 133 const SkPaint&); 134 virtual void drawData(const void*, size_t); 135 136private: 137 SkFactorySet* fFactorySet; // optional, only used if cross-process 138 SkGPipeController* fController; 139 SkWriter32& fWriter; 140 size_t fBlockSize; // amount allocated for writer 141 size_t fBytesNotified; 142 bool fDone; 143 144 SkRefCntSet fTypefaceSet; 145 146 uint32_t getTypefaceID(SkTypeface*); 147 148 inline void writeOp(DrawOps op, unsigned flags, unsigned data) { 149 fWriter.write32(DrawOp_packOpFlagData(op, flags, data)); 150 } 151 152 inline void writeOp(DrawOps op) { 153 fWriter.write32(DrawOp_packOpFlagData(op, 0, 0)); 154 } 155 156 bool needOpBytes(size_t size = 0); 157 158 inline void doNotify() { 159 if (!fDone) { 160 size_t bytes = fWriter.size() - fBytesNotified; 161 fController->notifyWritten(bytes); 162 fBytesNotified += bytes; 163 } 164 } 165 166 struct FlatData { 167 uint32_t fIndex; // always > 0 168 uint32_t fSize; 169 170 void* data() { return (char*)this + sizeof(*this); } 171 172 static int Compare(const FlatData* a, const FlatData* b) { 173 return memcmp(&a->fSize, &b->fSize, a->fSize + sizeof(a->fSize)); 174 } 175 }; 176 SkTDArray<FlatData*> fFlatArray; 177 int fCurrFlatIndex[kCount_PaintFlats]; 178 int flattenToIndex(SkFlattenable* obj, PaintFlats); 179 180 SkPaint fPaint; 181 void writePaint(const SkPaint&); 182 183 class AutoPipeNotify { 184 public: 185 AutoPipeNotify(SkGPipeCanvas* canvas) : fCanvas(canvas) {} 186 ~AutoPipeNotify() { fCanvas->doNotify(); } 187 private: 188 SkGPipeCanvas* fCanvas; 189 }; 190 friend class AutoPipeNotify; 191 192 typedef SkCanvas INHERITED; 193}; 194 195// return 0 for NULL (or unflattenable obj), or index-base-1 196int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) { 197 if (NULL == obj) { 198 return 0; 199 } 200 201 SkFlattenable::Factory fact = obj->getFactory(); 202 if (NULL == fact) { 203 return 0; 204 } 205 206 if (fFactorySet) { 207 uint32_t id = fFactorySet->find((void*)fact); 208 if (0 == id) { 209 const char* name = SkFlattenable::FactoryToName(fact); 210 if (NULL == name) { 211 return 0; 212 } 213 size_t len = strlen(name); 214 size_t size = SkWriter32::WriteStringSize(name, len); 215 if (!this->needOpBytes(size)) { 216 return 0; 217 } 218 unsigned id = fFactorySet->add(fact); 219 this->writeOp(kName_Flattenable_DrawOp, paintflat, id); 220 fWriter.writeString(name, len); 221 } 222 } 223 224 SkFlattenableWriteBuffer tmpWriter(1024); 225 tmpWriter.setFactoryRecorder(fFactorySet); 226 227 tmpWriter.writeFlattenable(obj); 228 size_t len = tmpWriter.size(); 229 size_t allocSize = len + sizeof(FlatData); 230 231 SkAutoSMalloc<1024> storage(allocSize); 232 FlatData* flat = (FlatData*)storage.get(); 233 flat->fSize = len; 234 tmpWriter.flatten(flat->data()); 235 236 int index = SkTSearch<FlatData>((const FlatData**)fFlatArray.begin(), 237 fFlatArray.count(), flat, sizeof(flat), 238 &FlatData::Compare); 239 if (index < 0) { 240 index = ~index; 241 FlatData* copy = (FlatData*)sk_malloc_throw(allocSize); 242 memcpy(copy, flat, allocSize); 243 *fFlatArray.insert(index) = copy; 244 // call this after the insert, so that count() will have been grown 245 copy->fIndex = fFlatArray.count(); 246// SkDebugf("--- add flattenable[%d] size=%d index=%d\n", paintflat, len, copy->fIndex); 247 248 if (this->needOpBytes(len)) { 249 this->writeOp(kDef_Flattenable_DrawOp, paintflat, copy->fIndex); 250 fWriter.write(copy->data(), len); 251 } 252 } 253 return fFlatArray[index]->fIndex; 254} 255 256/////////////////////////////////////////////////////////////////////////////// 257 258#define MIN_BLOCK_SIZE (16 * 1024) 259 260SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller, 261 SkWriter32* writer, SkFactorySet* fset) 262 : fWriter(*writer), fFactorySet(fset) { 263 fController = controller; 264 fDone = false; 265 fBlockSize = 0; // need first block from controller 266 sk_bzero(fCurrFlatIndex, sizeof(fCurrFlatIndex)); 267 268 // we need a device to limit our clip 269 // should the caller give us the bounds? 270 SkBitmap bitmap; 271 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32767, 32767); 272 SkDevice* device = SkNEW_ARGS(SkDevice, (this, bitmap, false)); 273 this->setDevice(device)->unref(); 274} 275 276SkGPipeCanvas::~SkGPipeCanvas() { 277 this->finish(); 278 279 fFlatArray.freeAll(); 280} 281 282bool SkGPipeCanvas::needOpBytes(size_t needed) { 283 if (fDone) { 284 return false; 285 } 286 287 needed += 4; // size of DrawOp atom 288 if (fWriter.size() + needed > fBlockSize) { 289 void* block = fController->requestBlock(MIN_BLOCK_SIZE, &fBlockSize); 290 if (NULL == block) { 291 fDone = true; 292 return false; 293 } 294 fWriter.reset(block, fBlockSize); 295 fBytesNotified = 0; 296 } 297 return true; 298} 299 300uint32_t SkGPipeCanvas::getTypefaceID(SkTypeface* face) { 301 uint32_t id = 0; // 0 means default/null typeface 302 if (face) { 303 id = fTypefaceSet.find(face); 304 if (0 == id) { 305 id = fTypefaceSet.add(face); 306 size_t size = writeTypeface(NULL, face); 307 if (this->needOpBytes(size)) { 308 this->writeOp(kDef_Typeface_DrawOp); 309 writeTypeface(&fWriter, face); 310 } 311 } 312 } 313 return id; 314} 315 316/////////////////////////////////////////////////////////////////////////////// 317 318#define NOTIFY_SETUP(canvas) \ 319 AutoPipeNotify apn(canvas) 320 321int SkGPipeCanvas::save(SaveFlags flags) { 322 NOTIFY_SETUP(this); 323 if (this->needOpBytes()) { 324 this->writeOp(kSave_DrawOp, 0, flags); 325 } 326 return this->INHERITED::save(flags); 327} 328 329int SkGPipeCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, 330 SaveFlags saveFlags) { 331 NOTIFY_SETUP(this); 332 size_t size = 0; 333 unsigned opFlags = 0; 334 335 if (bounds) { 336 opFlags |= kSaveLayer_HasBounds_DrawOpFlag; 337 size += sizeof(SkRect); 338 } 339 if (paint) { 340 opFlags |= kSaveLayer_HasPaint_DrawOpFlag; 341 this->writePaint(*paint); 342 } 343 344 if (this->needOpBytes(size)) { 345 this->writeOp(kSaveLayer_DrawOp, opFlags, saveFlags); 346 if (bounds) { 347 fWriter.writeRect(*bounds); 348 } 349 } 350 351 // we just pass on the save, so we don't create a layer 352 return this->INHERITED::save(saveFlags); 353} 354 355void SkGPipeCanvas::restore() { 356 NOTIFY_SETUP(this); 357 if (this->needOpBytes()) { 358 this->writeOp(kRestore_DrawOp); 359 } 360 this->INHERITED::restore(); 361} 362 363bool SkGPipeCanvas::translate(SkScalar dx, SkScalar dy) { 364 if (dx || dy) { 365 NOTIFY_SETUP(this); 366 if (this->needOpBytes(2 * sizeof(SkScalar))) { 367 this->writeOp(kTranslate_DrawOp); 368 fWriter.writeScalar(dx); 369 fWriter.writeScalar(dy); 370 } 371 } 372 return this->INHERITED::translate(dx, dy); 373} 374 375bool SkGPipeCanvas::scale(SkScalar sx, SkScalar sy) { 376 if (sx || sy) { 377 NOTIFY_SETUP(this); 378 if (this->needOpBytes(2 * sizeof(SkScalar))) { 379 this->writeOp(kScale_DrawOp); 380 fWriter.writeScalar(sx); 381 fWriter.writeScalar(sy); 382 } 383 } 384 return this->INHERITED::scale(sx, sy); 385} 386 387bool SkGPipeCanvas::rotate(SkScalar degrees) { 388 if (degrees) { 389 NOTIFY_SETUP(this); 390 if (this->needOpBytes(sizeof(SkScalar))) { 391 this->writeOp(kRotate_DrawOp); 392 fWriter.writeScalar(degrees); 393 } 394 } 395 return this->INHERITED::rotate(degrees); 396} 397 398bool SkGPipeCanvas::skew(SkScalar sx, SkScalar sy) { 399 if (sx || sy) { 400 NOTIFY_SETUP(this); 401 if (this->needOpBytes(2 * sizeof(SkScalar))) { 402 this->writeOp(kSkew_DrawOp); 403 fWriter.writeScalar(sx); 404 fWriter.writeScalar(sy); 405 } 406 } 407 return this->INHERITED::skew(sx, sy); 408} 409 410bool SkGPipeCanvas::concat(const SkMatrix& matrix) { 411 if (!matrix.isIdentity()) { 412 NOTIFY_SETUP(this); 413 if (this->needOpBytes(matrix.flatten(NULL))) { 414 this->writeOp(kConcat_DrawOp); 415 SkWriteMatrix(&fWriter, matrix); 416 } 417 } 418 return this->INHERITED::concat(matrix); 419} 420 421void SkGPipeCanvas::setMatrix(const SkMatrix& matrix) { 422 NOTIFY_SETUP(this); 423 if (this->needOpBytes(matrix.flatten(NULL))) { 424 this->writeOp(kSetMatrix_DrawOp); 425 SkWriteMatrix(&fWriter, matrix); 426 } 427 this->INHERITED::setMatrix(matrix); 428} 429 430bool SkGPipeCanvas::clipRect(const SkRect& rect, SkRegion::Op rgnOp) { 431 NOTIFY_SETUP(this); 432 if (this->needOpBytes(sizeof(SkRect))) { 433 this->writeOp(kClipRect_DrawOp, 0, rgnOp); 434 fWriter.writeRect(rect); 435 } 436 return this->INHERITED::clipRect(rect, rgnOp); 437} 438 439bool SkGPipeCanvas::clipPath(const SkPath& path, SkRegion::Op rgnOp) { 440 NOTIFY_SETUP(this); 441 if (this->needOpBytes(estimateFlattenSize(path))) { 442 this->writeOp(kClipPath_DrawOp, 0, rgnOp); 443 path.flatten(fWriter); 444 } 445 // we just pass on the bounds of the path 446 return this->INHERITED::clipRect(path.getBounds(), rgnOp); 447} 448 449bool SkGPipeCanvas::clipRegion(const SkRegion& region, SkRegion::Op rgnOp) { 450 NOTIFY_SETUP(this); 451 if (this->needOpBytes(region.flatten(NULL))) { 452 this->writeOp(kClipRegion_DrawOp, 0, rgnOp); 453 SkWriteRegion(&fWriter, region); 454 } 455 return this->INHERITED::clipRegion(region, rgnOp); 456} 457 458/////////////////////////////////////////////////////////////////////////////// 459 460void SkGPipeCanvas::clear(SkColor color) { 461 NOTIFY_SETUP(this); 462 unsigned flags = 0; 463 if (color) { 464 flags |= kClear_HasColor_DrawOpFlag; 465 } 466 if (this->needOpBytes(sizeof(SkColor))) { 467 this->writeOp(kDrawClear_DrawOp, flags, 0); 468 if (color) { 469 fWriter.write32(color); 470 } 471 } 472} 473 474void SkGPipeCanvas::drawPaint(const SkPaint& paint) { 475 NOTIFY_SETUP(this); 476 this->writePaint(paint); 477 if (this->needOpBytes()) { 478 this->writeOp(kDrawPaint_DrawOp); 479 } 480} 481 482void SkGPipeCanvas::drawPoints(PointMode mode, size_t count, 483 const SkPoint pts[], const SkPaint& paint) { 484 if (count) { 485 NOTIFY_SETUP(this); 486 this->writePaint(paint); 487 if (this->needOpBytes(4 + count * sizeof(SkPoint))) { 488 this->writeOp(kDrawPoints_DrawOp, mode, 0); 489 fWriter.write32(count); 490 fWriter.write(pts, count * sizeof(SkPoint)); 491 } 492 } 493} 494 495void SkGPipeCanvas::drawRect(const SkRect& rect, const SkPaint& paint) { 496 NOTIFY_SETUP(this); 497 this->writePaint(paint); 498 if (this->needOpBytes(sizeof(SkRect))) { 499 this->writeOp(kDrawRect_DrawOp); 500 fWriter.writeRect(rect); 501 } 502} 503 504void SkGPipeCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 505 NOTIFY_SETUP(this); 506 this->writePaint(paint); 507 if (this->needOpBytes(estimateFlattenSize(path))) { 508 this->writeOp(kDrawPath_DrawOp); 509 path.flatten(fWriter); 510 } 511} 512 513void SkGPipeCanvas::drawBitmap(const SkBitmap&, SkScalar left, SkScalar top, 514 const SkPaint*) { 515 UNIMPLEMENTED 516} 517 518void SkGPipeCanvas::drawBitmapRect(const SkBitmap&, const SkIRect* src, 519 const SkRect& dst, const SkPaint*) { 520 UNIMPLEMENTED 521} 522 523void SkGPipeCanvas::drawBitmapMatrix(const SkBitmap&, const SkMatrix&, 524 const SkPaint*) { 525 UNIMPLEMENTED 526} 527 528void SkGPipeCanvas::drawSprite(const SkBitmap&, int left, int top, 529 const SkPaint*) { 530 UNIMPLEMENTED 531} 532 533void SkGPipeCanvas::drawText(const void* text, size_t byteLength, SkScalar x, 534 SkScalar y, const SkPaint& paint) { 535 if (byteLength) { 536 NOTIFY_SETUP(this); 537 this->writePaint(paint); 538 if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar))) { 539 this->writeOp(kDrawText_DrawOp); 540 fWriter.write32(byteLength); 541 fWriter.writePad(text, byteLength); 542 fWriter.writeScalar(x); 543 fWriter.writeScalar(y); 544 } 545 } 546} 547 548void SkGPipeCanvas::drawPosText(const void* text, size_t byteLength, 549 const SkPoint pos[], const SkPaint& paint) { 550 if (byteLength) { 551 NOTIFY_SETUP(this); 552 this->writePaint(paint); 553 int count = paint.textToGlyphs(text, byteLength, NULL); 554 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPoint))) { 555 this->writeOp(kDrawPosText_DrawOp); 556 fWriter.write32(byteLength); 557 fWriter.writePad(text, byteLength); 558 fWriter.write32(count); 559 fWriter.write(pos, count * sizeof(SkPoint)); 560 } 561 } 562} 563 564void SkGPipeCanvas::drawPosTextH(const void* text, size_t byteLength, 565 const SkScalar xpos[], SkScalar constY, 566 const SkPaint& paint) { 567 if (byteLength) { 568 NOTIFY_SETUP(this); 569 this->writePaint(paint); 570 int count = paint.textToGlyphs(text, byteLength, NULL); 571 if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkScalar) + 4)) { 572 this->writeOp(kDrawPosTextH_DrawOp); 573 fWriter.write32(byteLength); 574 fWriter.writePad(text, byteLength); 575 fWriter.write32(count); 576 fWriter.write(xpos, count * sizeof(SkScalar)); 577 fWriter.writeScalar(constY); 578 } 579 } 580} 581 582void SkGPipeCanvas::drawTextOnPath(const void* text, size_t byteLength, 583 const SkPath& path, const SkMatrix* matrix, 584 const SkPaint& paint) { 585 if (byteLength) { 586 NOTIFY_SETUP(this); 587 unsigned flags = 0; 588 size_t size = 4 + SkAlign4(byteLength) + estimateFlattenSize(path); 589 if (matrix) { 590 flags |= kDrawTextOnPath_HasMatrix_DrawOpFlag; 591 size += matrix->flatten(NULL); 592 } 593 this->writePaint(paint); 594 if (this->needOpBytes(size)) { 595 this->writeOp(kDrawTextOnPath_DrawOp, flags, 0); 596 597 fWriter.write32(byteLength); 598 fWriter.writePad(text, byteLength); 599 600 path.flatten(fWriter); 601 if (matrix) { 602 SkWriteMatrix(&fWriter, *matrix); 603 } 604 } 605 } 606} 607 608void SkGPipeCanvas::drawPicture(SkPicture& picture) { 609 // we want to playback the picture into individual draw calls 610 this->INHERITED::drawPicture(picture); 611} 612 613void SkGPipeCanvas::drawShape(SkShape* shape) { 614 UNIMPLEMENTED 615} 616 617void SkGPipeCanvas::drawVertices(VertexMode mode, int vertexCount, 618 const SkPoint vertices[], const SkPoint texs[], 619 const SkColor colors[], SkXfermode*, 620 const uint16_t indices[], int indexCount, 621 const SkPaint& paint) { 622 if (0 == vertexCount) { 623 return; 624 } 625 626 NOTIFY_SETUP(this); 627 size_t size = 4 + vertexCount * sizeof(SkPoint); 628 this->writePaint(paint); 629 unsigned flags = 0; 630 if (texs) { 631 flags |= kDrawVertices_HasTexs_DrawOpFlag; 632 size += vertexCount * sizeof(SkPoint); 633 } 634 if (colors) { 635 flags |= kDrawVertices_HasColors_DrawOpFlag; 636 size += vertexCount * sizeof(SkColor); 637 } 638 if (indices && indexCount > 0) { 639 flags |= kDrawVertices_HasIndices_DrawOpFlag; 640 size += 4 + SkAlign4(indexCount * sizeof(uint16_t)); 641 } 642 643 if (this->needOpBytes(size)) { 644 this->writeOp(kDrawVertices_DrawOp, flags, 0); 645 fWriter.write32(mode); 646 fWriter.write32(vertexCount); 647 fWriter.write(vertices, vertexCount * sizeof(SkPoint)); 648 if (texs) { 649 fWriter.write(texs, vertexCount * sizeof(SkPoint)); 650 } 651 if (colors) { 652 fWriter.write(colors, vertexCount * sizeof(SkColor)); 653 } 654 655 // TODO: flatten xfermode 656 657 if (indices && indexCount > 0) { 658 fWriter.write32(indexCount); 659 fWriter.writePad(indices, indexCount * sizeof(uint16_t)); 660 } 661 } 662} 663 664void SkGPipeCanvas::drawData(const void* ptr, size_t size) { 665 if (size && ptr) { 666 NOTIFY_SETUP(this); 667 unsigned data = 0; 668 if (size < (1 << DRAWOPS_DATA_BITS)) { 669 data = (unsigned)size; 670 } 671 if (this->needOpBytes(4 + SkAlign4(size))) { 672 this->writeOp(kDrawData_DrawOp, 0, data); 673 if (0 == data) { 674 fWriter.write32(size); 675 } 676 fWriter.writePad(ptr, size); 677 } 678 } 679} 680 681/////////////////////////////////////////////////////////////////////////////// 682 683template <typename T> uint32_t castToU32(T value) { 684 union { 685 T fSrc; 686 uint32_t fDst; 687 } data; 688 data.fSrc = value; 689 return data.fDst; 690} 691 692void SkGPipeCanvas::writePaint(const SkPaint& paint) { 693 SkPaint& base = fPaint; 694 uint32_t storage[32]; 695 uint32_t* ptr = storage; 696 697 if (base.getFlags() != paint.getFlags()) { 698 *ptr++ = PaintOp_packOpData(kFlags_PaintOp, paint.getFlags()); 699 base.setFlags(paint.getFlags()); 700 } 701 if (base.getColor() != paint.getColor()) { 702 *ptr++ = PaintOp_packOp(kColor_PaintOp); 703 *ptr++ = paint.getColor(); 704 base.setColor(paint.getColor()); 705 } 706 if (base.getStyle() != paint.getStyle()) { 707 *ptr++ = PaintOp_packOpData(kStyle_PaintOp, paint.getStyle()); 708 base.setStyle(paint.getStyle()); 709 } 710 if (base.getStrokeJoin() != paint.getStrokeJoin()) { 711 *ptr++ = PaintOp_packOpData(kJoin_PaintOp, paint.getStrokeJoin()); 712 base.setStrokeJoin(paint.getStrokeJoin()); 713 } 714 if (base.getStrokeCap() != paint.getStrokeCap()) { 715 *ptr++ = PaintOp_packOpData(kCap_PaintOp, paint.getStrokeCap()); 716 base.setStrokeCap(paint.getStrokeCap()); 717 } 718 if (base.getStrokeWidth() != paint.getStrokeWidth()) { 719 *ptr++ = PaintOp_packOp(kWidth_PaintOp); 720 *ptr++ = castToU32(paint.getStrokeWidth()); 721 base.setStrokeWidth(paint.getStrokeWidth()); 722 } 723 if (base.getStrokeMiter() != paint.getStrokeMiter()) { 724 *ptr++ = PaintOp_packOp(kMiter_PaintOp); 725 *ptr++ = castToU32(paint.getStrokeMiter()); 726 base.setStrokeMiter(paint.getStrokeMiter()); 727 } 728 if (base.getTextEncoding() != paint.getTextEncoding()) { 729 *ptr++ = PaintOp_packOpData(kEncoding_PaintOp, paint.getTextEncoding()); 730 base.setTextEncoding(paint.getTextEncoding()); 731 } 732 if (base.getHinting() != paint.getHinting()) { 733 *ptr++ = PaintOp_packOpData(kHinting_PaintOp, paint.getHinting()); 734 base.setHinting(paint.getHinting()); 735 } 736 if (base.getTextAlign() != paint.getTextAlign()) { 737 *ptr++ = PaintOp_packOpData(kAlign_PaintOp, paint.getTextAlign()); 738 base.setTextAlign(paint.getTextAlign()); 739 } 740 if (base.getTextSize() != paint.getTextSize()) { 741 *ptr++ = PaintOp_packOp(kTextSize_PaintOp); 742 *ptr++ = castToU32(paint.getTextSize()); 743 base.setTextSize(paint.getTextSize()); 744 } 745 if (base.getTextScaleX() != paint.getTextScaleX()) { 746 *ptr++ = PaintOp_packOp(kTextScaleX_PaintOp); 747 *ptr++ = castToU32(paint.getTextScaleX()); 748 base.setTextScaleX(paint.getTextScaleX()); 749 } 750 if (base.getTextSkewX() != paint.getTextSkewX()) { 751 *ptr++ = PaintOp_packOp(kTextSkewX_PaintOp); 752 *ptr++ = castToU32(paint.getTextSkewX()); 753 base.setTextSkewX(paint.getTextSkewX()); 754 } 755 756 if (!SkTypeface::Equal(base.getTypeface(), paint.getTypeface())) { 757 uint32_t id = this->getTypefaceID(paint.getTypeface()); 758 *ptr++ = PaintOp_packOpData(kTypeface_PaintOp, id); 759 base.setTypeface(paint.getTypeface()); 760 } 761 762 for (int i = 0; i < kCount_PaintFlats; i++) { 763 int index = this->flattenToIndex(get_paintflat(paint, i), (PaintFlats)i); 764 SkASSERT(index >= 0 && index <= fFlatArray.count()); 765 if (index != fCurrFlatIndex[i]) { 766 *ptr++ = PaintOp_packOpFlagData(kFlatIndex_PaintOp, i, index); 767 fCurrFlatIndex[i] = index; 768 } 769 } 770 771 size_t size = (char*)ptr - (char*)storage; 772 if (size && this->needOpBytes(size)) { 773 this->writeOp(kPaintOp_DrawOp, 0, size); 774 fWriter.write(storage, size); 775 for (size_t i = 0; i < size/4; i++) { 776// SkDebugf("[%d] %08X\n", i, storage[i]); 777 } 778 } 779} 780 781/////////////////////////////////////////////////////////////////////////////// 782 783#include "SkGPipe.h" 784 785SkGPipeWriter::SkGPipeWriter() : fWriter(0) { 786 fCanvas = NULL; 787} 788 789SkGPipeWriter::~SkGPipeWriter() { 790 this->endRecording(); 791 SkSafeUnref(fCanvas); 792} 793 794SkCanvas* SkGPipeWriter::startRecording(SkGPipeController* controller, 795 uint32_t flags) { 796 if (NULL == fCanvas) { 797 fWriter.reset(NULL, 0); 798 fFactorySet.reset(); 799 fCanvas = SkNEW_ARGS(SkGPipeCanvas, (controller, &fWriter, 800 (flags & kCrossProcess_Flag) ? 801 &fFactorySet : NULL)); 802 } 803 return fCanvas; 804} 805 806void SkGPipeWriter::endRecording() { 807 if (fCanvas) { 808 fCanvas->finish(); 809 fCanvas->unref(); 810 fCanvas = NULL; 811 } 812} 813 814