Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(142)

Side by Side Diff: src/pdf/SkPDFDevice.cpp

Issue 1839633003: SkPDF: PDFDevice::ContentEntry now implemented with SinglyLinkedList (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: 2016-03-28 (Monday) 13:12:45 EDT Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/pdf/SkPDFDevice.h ('k') | src/pdf/SkSinglyLinkedList.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2011 Google Inc. 2 * Copyright 2011 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkPDFDevice.h" 8 #include "SkPDFDevice.h"
9 9
10 #include "SkAnnotationKeys.h" 10 #include "SkAnnotationKeys.h"
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 // the passed parameters. 174 // the passed parameters.
175 content->writeText("1 0 "); 175 content->writeText("1 0 ");
176 SkPDFUtils::AppendScalar(0 - textSkewX, content); 176 SkPDFUtils::AppendScalar(0 - textSkewX, content);
177 content->writeText(" -1 "); 177 content->writeText(" -1 ");
178 SkPDFUtils::AppendScalar(x, content); 178 SkPDFUtils::AppendScalar(x, content);
179 content->writeText(" "); 179 content->writeText(" ");
180 SkPDFUtils::AppendScalar(y, content); 180 SkPDFUtils::AppendScalar(y, content);
181 content->writeText(" Tm\n"); 181 content->writeText(" Tm\n");
182 } 182 }
183 183
184 // It is important to not confuse GraphicStateEntry with SkPDFGraphicState, the 184 SkPDFDevice::GraphicStateEntry::GraphicStateEntry()
185 // later being our representation of an object in the PDF file. 185 : fColor(SK_ColorBLACK)
186 struct GraphicStateEntry { 186 , fTextScaleX(SK_Scalar1)
187 GraphicStateEntry(); 187 , fTextFill(SkPaint::kFill_Style)
188 188 , fShaderIndex(-1)
189 // Compare the fields we care about when setting up a new content entry. 189 , fGraphicStateIndex(-1)
190 bool compareInitialState(const GraphicStateEntry& b); 190 , fFont(nullptr)
191 191 , fTextSize(SK_ScalarNaN) {
192 SkMatrix fMatrix;
193 // We can't do set operations on Paths, though PDF natively supports
194 // intersect. If the clip stack does anything other than intersect,
195 // we have to fall back to the region. Treat fClipStack as authoritative.
196 // See http://code.google.com/p/skia/issues/detail?id=221
197 SkClipStack fClipStack;
198 SkRegion fClipRegion;
199
200 // When emitting the content entry, we will ensure the graphic state
201 // is set to these values first.
202 SkColor fColor;
203 SkScalar fTextScaleX; // Zero means we don't care what the value is.
204 SkPaint::Style fTextFill; // Only if TextScaleX is non-zero.
205 int fShaderIndex;
206 int fGraphicStateIndex;
207
208 // We may change the font (i.e. for Type1 support) within a
209 // ContentEntry. This is the one currently in effect, or nullptr if none.
210 SkPDFFont* fFont;
211 // In PDF, text size has no default value. It is only valid if fFont is
212 // not nullptr.
213 SkScalar fTextSize;
214 };
215
216 GraphicStateEntry::GraphicStateEntry() : fColor(SK_ColorBLACK),
217 fTextScaleX(SK_Scalar1),
218 fTextFill(SkPaint::kFill_Style),
219 fShaderIndex(-1),
220 fGraphicStateIndex(-1),
221 fFont(nullptr),
222 fTextSize(SK_ScalarNaN) {
223 fMatrix.reset(); 192 fMatrix.reset();
224 } 193 }
225 194
226 bool GraphicStateEntry::compareInitialState(const GraphicStateEntry& cur) { 195 bool SkPDFDevice::GraphicStateEntry::compareInitialState(
196 const GraphicStateEntry& cur) {
227 return fColor == cur.fColor && 197 return fColor == cur.fColor &&
228 fShaderIndex == cur.fShaderIndex && 198 fShaderIndex == cur.fShaderIndex &&
229 fGraphicStateIndex == cur.fGraphicStateIndex && 199 fGraphicStateIndex == cur.fGraphicStateIndex &&
230 fMatrix == cur.fMatrix && 200 fMatrix == cur.fMatrix &&
231 fClipStack == cur.fClipStack && 201 fClipStack == cur.fClipStack &&
232 (fTextScaleX == 0 || 202 (fTextScaleX == 0 ||
233 (fTextScaleX == cur.fTextScaleX && fTextFill == cur.fTextFill)); 203 (fTextScaleX == cur.fTextScaleX && fTextFill == cur.fTextFill));
234 } 204 }
235 205
236 class GraphicStackState { 206 class GraphicStackState {
237 public: 207 public:
238 GraphicStackState(const SkClipStack& existingClipStack, 208 GraphicStackState(const SkClipStack& existingClipStack,
239 const SkRegion& existingClipRegion, 209 const SkRegion& existingClipRegion,
240 SkWStream* contentStream) 210 SkWStream* contentStream)
241 : fStackDepth(0), 211 : fStackDepth(0),
242 fContentStream(contentStream) { 212 fContentStream(contentStream) {
243 fEntries[0].fClipStack = existingClipStack; 213 fEntries[0].fClipStack = existingClipStack;
244 fEntries[0].fClipRegion = existingClipRegion; 214 fEntries[0].fClipRegion = existingClipRegion;
245 } 215 }
246 216
247 void updateClip(const SkClipStack& clipStack, const SkRegion& clipRegion, 217 void updateClip(const SkClipStack& clipStack, const SkRegion& clipRegion,
248 const SkPoint& translation); 218 const SkPoint& translation);
249 void updateMatrix(const SkMatrix& matrix); 219 void updateMatrix(const SkMatrix& matrix);
250 void updateDrawingState(const GraphicStateEntry& state); 220 void updateDrawingState(const SkPDFDevice::GraphicStateEntry& state);
251 221
252 void drainStack(); 222 void drainStack();
253 223
254 private: 224 private:
255 void push(); 225 void push();
256 void pop(); 226 void pop();
257 GraphicStateEntry* currentEntry() { return &fEntries[fStackDepth]; } 227 SkPDFDevice::GraphicStateEntry* currentEntry() { return &fEntries[fStackDept h]; }
258 228
259 // Conservative limit on save depth, see impl. notes in PDF 1.4 spec. 229 // Conservative limit on save depth, see impl. notes in PDF 1.4 spec.
260 static const int kMaxStackDepth = 12; 230 static const int kMaxStackDepth = 12;
261 GraphicStateEntry fEntries[kMaxStackDepth + 1]; 231 SkPDFDevice::GraphicStateEntry fEntries[kMaxStackDepth + 1];
262 int fStackDepth; 232 int fStackDepth;
263 SkWStream* fContentStream; 233 SkWStream* fContentStream;
264 }; 234 };
265 235
266 void GraphicStackState::drainStack() { 236 void GraphicStackState::drainStack() {
267 while (fStackDepth) { 237 while (fStackDepth) {
268 pop(); 238 pop();
269 } 239 }
270 } 240 }
271 241
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after
516 } 486 }
517 if (matrix.getType() == SkMatrix::kIdentity_Mask) { 487 if (matrix.getType() == SkMatrix::kIdentity_Mask) {
518 return; 488 return;
519 } 489 }
520 490
521 push(); 491 push();
522 SkPDFUtils::AppendTransform(matrix, fContentStream); 492 SkPDFUtils::AppendTransform(matrix, fContentStream);
523 currentEntry()->fMatrix = matrix; 493 currentEntry()->fMatrix = matrix;
524 } 494 }
525 495
526 void GraphicStackState::updateDrawingState(const GraphicStateEntry& state) { 496 void GraphicStackState::updateDrawingState(const SkPDFDevice::GraphicStateEntry& state) {
527 // PDF treats a shader as a color, so we only set one or the other. 497 // PDF treats a shader as a color, so we only set one or the other.
528 if (state.fShaderIndex >= 0) { 498 if (state.fShaderIndex >= 0) {
529 if (state.fShaderIndex != currentEntry()->fShaderIndex) { 499 if (state.fShaderIndex != currentEntry()->fShaderIndex) {
530 SkPDFUtils::ApplyPattern(state.fShaderIndex, fContentStream); 500 SkPDFUtils::ApplyPattern(state.fShaderIndex, fContentStream);
531 currentEntry()->fShaderIndex = state.fShaderIndex; 501 currentEntry()->fShaderIndex = state.fShaderIndex;
532 } 502 }
533 } else { 503 } else {
534 if (state.fColor != currentEntry()->fColor || 504 if (state.fColor != currentEntry()->fColor ||
535 currentEntry()->fShaderIndex >= 0) { 505 currentEntry()->fShaderIndex >= 0) {
536 emit_pdf_color(state.fColor, fContentStream); 506 emit_pdf_color(state.fColor, fContentStream);
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
582 (layerPaint && not_supported_for_layers(*layerPaint))) { 552 (layerPaint && not_supported_for_layers(*layerPaint))) {
583 return nullptr; 553 return nullptr;
584 } 554 }
585 SkISize size = SkISize::Make(cinfo.fInfo.width(), cinfo.fInfo.height()); 555 SkISize size = SkISize::Make(cinfo.fInfo.width(), cinfo.fInfo.height());
586 return SkPDFDevice::Create(size, fRasterDpi, fDocument); 556 return SkPDFDevice::Create(size, fRasterDpi, fDocument);
587 } 557 }
588 558
589 SkPDFCanon* SkPDFDevice::getCanon() const { return fDocument->canon(); } 559 SkPDFCanon* SkPDFDevice::getCanon() const { return fDocument->canon(); }
590 560
591 561
592 struct ContentEntry {
593 GraphicStateEntry fState;
594 SkDynamicMemoryWStream fContent;
595 SkAutoTDelete<ContentEntry> fNext;
596
597 // If the stack is too deep we could get Stack Overflow.
598 // So we manually destruct the object.
599 ~ContentEntry() {
600 ContentEntry* val = fNext.release();
601 while (val != nullptr) {
602 ContentEntry* valNext = val->fNext.release();
603 // When the destructor is called, fNext is nullptr and exits.
604 delete val;
605 val = valNext;
606 }
607 }
608 };
609 562
610 // A helper class to automatically finish a ContentEntry at the end of a 563 // A helper class to automatically finish a ContentEntry at the end of a
611 // drawing method and maintain the state needed between set up and finish. 564 // drawing method and maintain the state needed between set up and finish.
612 class ScopedContentEntry { 565 class ScopedContentEntry {
613 public: 566 public:
614 ScopedContentEntry(SkPDFDevice* device, const SkDraw& draw, 567 ScopedContentEntry(SkPDFDevice* device, const SkDraw& draw,
615 const SkPaint& paint, bool hasText = false) 568 const SkPaint& paint, bool hasText = false)
616 : fDevice(device), 569 : fDevice(device),
617 fContentEntry(nullptr), 570 fContentEntry(nullptr),
618 fXfermode(SkXfermode::kSrcOver_Mode), 571 fXfermode(SkXfermode::kSrcOver_Mode),
(...skipping 14 matching lines...) Expand all
633 if (fContentEntry) { 586 if (fContentEntry) {
634 SkPath* shape = &fShape; 587 SkPath* shape = &fShape;
635 if (shape->isEmpty()) { 588 if (shape->isEmpty()) {
636 shape = nullptr; 589 shape = nullptr;
637 } 590 }
638 fDevice->finishContentEntry(fXfermode, fDstFormXObject, shape); 591 fDevice->finishContentEntry(fXfermode, fDstFormXObject, shape);
639 } 592 }
640 SkSafeUnref(fDstFormXObject); 593 SkSafeUnref(fDstFormXObject);
641 } 594 }
642 595
643 ContentEntry* entry() { return fContentEntry; } 596 SkPDFDevice::ContentEntry* entry() { return fContentEntry; }
644 597
645 /* Returns true when we explicitly need the shape of the drawing. */ 598 /* Returns true when we explicitly need the shape of the drawing. */
646 bool needShape() { 599 bool needShape() {
647 switch (fXfermode) { 600 switch (fXfermode) {
648 case SkXfermode::kClear_Mode: 601 case SkXfermode::kClear_Mode:
649 case SkXfermode::kSrc_Mode: 602 case SkXfermode::kSrc_Mode:
650 case SkXfermode::kSrcIn_Mode: 603 case SkXfermode::kSrcIn_Mode:
651 case SkXfermode::kSrcOut_Mode: 604 case SkXfermode::kSrcOut_Mode:
652 case SkXfermode::kDstIn_Mode: 605 case SkXfermode::kDstIn_Mode:
653 case SkXfermode::kDstOut_Mode: 606 case SkXfermode::kDstOut_Mode:
(...skipping 17 matching lines...) Expand all
671 /* If the shape is different than the alpha component of the content, then 624 /* If the shape is different than the alpha component of the content, then
672 * setShape should be called with the shape. In particular, images and 625 * setShape should be called with the shape. In particular, images and
673 * devices have rectangular shape. 626 * devices have rectangular shape.
674 */ 627 */
675 void setShape(const SkPath& shape) { 628 void setShape(const SkPath& shape) {
676 fShape = shape; 629 fShape = shape;
677 } 630 }
678 631
679 private: 632 private:
680 SkPDFDevice* fDevice; 633 SkPDFDevice* fDevice;
681 ContentEntry* fContentEntry; 634 SkPDFDevice::ContentEntry* fContentEntry;
682 SkXfermode::Mode fXfermode; 635 SkXfermode::Mode fXfermode;
683 SkPDFFormXObject* fDstFormXObject; 636 SkPDFFormXObject* fDstFormXObject;
684 SkPath fShape; 637 SkPath fShape;
685 638
686 void init(const SkClipStack* clipStack, const SkRegion& clipRegion, 639 void init(const SkClipStack* clipStack, const SkRegion& clipRegion,
687 const SkMatrix& matrix, const SkPaint& paint, bool hasText) { 640 const SkMatrix& matrix, const SkPaint& paint, bool hasText) {
688 // Shape has to be flatten before we get here. 641 // Shape has to be flatten before we get here.
689 if (matrix.hasPerspective()) { 642 if (matrix.hasPerspective()) {
690 NOT_IMPLEMENTED(!matrix.hasPerspective(), false); 643 NOT_IMPLEMENTED(!matrix.hasPerspective(), false);
691 return; 644 return;
692 } 645 }
693 if (paint.getXfermode()) { 646 if (paint.getXfermode()) {
694 paint.getXfermode()->asMode(&fXfermode); 647 paint.getXfermode()->asMode(&fXfermode);
695 } 648 }
696 fContentEntry = fDevice->setUpContentEntry(clipStack, clipRegion, 649 fContentEntry = fDevice->setUpContentEntry(clipStack, clipRegion,
697 matrix, paint, hasText, 650 matrix, paint, hasText,
698 &fDstFormXObject); 651 &fDstFormXObject);
699 } 652 }
700 }; 653 };
701 654
702 //////////////////////////////////////////////////////////////////////////////// 655 ////////////////////////////////////////////////////////////////////////////////
703 656
704 SkPDFDevice::SkPDFDevice(SkISize pageSize, SkScalar rasterDpi, SkPDFDocument* do c, bool flip) 657 SkPDFDevice::SkPDFDevice(SkISize pageSize, SkScalar rasterDpi, SkPDFDocument* do c, bool flip)
705 : INHERITED(SkSurfaceProps(0, kUnknown_SkPixelGeometry)) 658 : INHERITED(SkSurfaceProps(0, kUnknown_SkPixelGeometry))
706 , fPageSize(pageSize) 659 , fPageSize(pageSize)
707 , fContentSize(pageSize) 660 , fContentSize(pageSize)
708 , fExistingClipRegion(SkIRect::MakeSize(pageSize)) 661 , fExistingClipRegion(SkIRect::MakeSize(pageSize))
709 , fLastContentEntry(nullptr)
710 , fClipStack(nullptr) 662 , fClipStack(nullptr)
711 , fFontGlyphUsage(new SkPDFGlyphSetMap) 663 , fFontGlyphUsage(new SkPDFGlyphSetMap)
712 , fRasterDpi(rasterDpi) 664 , fRasterDpi(rasterDpi)
713 , fDocument(doc) { 665 , fDocument(doc) {
714 SkASSERT(pageSize.width() > 0); 666 SkASSERT(pageSize.width() > 0);
715 SkASSERT(pageSize.height() > 0); 667 SkASSERT(pageSize.height() > 0);
716 fLegacyBitmap.setInfo( 668 fLegacyBitmap.setInfo(
717 SkImageInfo::MakeUnknown(pageSize.width(), pageSize.height())); 669 SkImageInfo::MakeUnknown(pageSize.width(), pageSize.height()));
718 if (flip) { 670 if (flip) {
719 // Skia generally uses the top left as the origin but PDF 671 // Skia generally uses the top left as the origin but PDF
720 // natively has the origin at the bottom left. This matrix 672 // natively has the origin at the bottom left. This matrix
721 // corrects for that. But that only needs to be done once, we 673 // corrects for that. But that only needs to be done once, we
722 // don't do it when layering. 674 // don't do it when layering.
723 fInitialTransform.setTranslate(0, SkIntToScalar(pageSize.fHeight)); 675 fInitialTransform.setTranslate(0, SkIntToScalar(pageSize.fHeight));
724 fInitialTransform.preScale(SK_Scalar1, -SK_Scalar1); 676 fInitialTransform.preScale(SK_Scalar1, -SK_Scalar1);
725 } else { 677 } else {
726 fInitialTransform.setIdentity(); 678 fInitialTransform.setIdentity();
727 } 679 }
728 } 680 }
729 681
730 SkPDFDevice::~SkPDFDevice() { 682 SkPDFDevice::~SkPDFDevice() {
731 this->cleanUp(true); 683 this->cleanUp(true);
732 } 684 }
733 685
734 void SkPDFDevice::init() { 686 void SkPDFDevice::init() {
735 fContentEntries.reset(); 687 fContentEntries.reset();
736 fLastContentEntry = nullptr;
737 if (fFontGlyphUsage.get() == nullptr) { 688 if (fFontGlyphUsage.get() == nullptr) {
738 fFontGlyphUsage.reset(new SkPDFGlyphSetMap); 689 fFontGlyphUsage.reset(new SkPDFGlyphSetMap);
739 } 690 }
740 } 691 }
741 692
742 void SkPDFDevice::cleanUp(bool clearFontUsage) { 693 void SkPDFDevice::cleanUp(bool clearFontUsage) {
743 fGraphicStateResources.unrefAll(); 694 fGraphicStateResources.unrefAll();
744 fXObjectResources.unrefAll(); 695 fXObjectResources.unrefAll();
745 fFontResources.unrefAll(); 696 fFontResources.unrefAll();
746 fShaderResources.unrefAll(); 697 fShaderResources.unrefAll();
(...skipping 17 matching lines...) Expand all
764 void SkPDFDevice::drawPaint(const SkDraw& d, const SkPaint& paint) { 715 void SkPDFDevice::drawPaint(const SkDraw& d, const SkPaint& paint) {
765 SkPaint newPaint = paint; 716 SkPaint newPaint = paint;
766 replace_srcmode_on_opaque_paint(&newPaint); 717 replace_srcmode_on_opaque_paint(&newPaint);
767 718
768 newPaint.setStyle(SkPaint::kFill_Style); 719 newPaint.setStyle(SkPaint::kFill_Style);
769 ScopedContentEntry content(this, d, newPaint); 720 ScopedContentEntry content(this, d, newPaint);
770 internalDrawPaint(newPaint, content.entry()); 721 internalDrawPaint(newPaint, content.entry());
771 } 722 }
772 723
773 void SkPDFDevice::internalDrawPaint(const SkPaint& paint, 724 void SkPDFDevice::internalDrawPaint(const SkPaint& paint,
774 ContentEntry* contentEntry) { 725 SkPDFDevice::ContentEntry* contentEntry) {
775 if (!contentEntry) { 726 if (!contentEntry) {
776 return; 727 return;
777 } 728 }
778 SkRect bbox = SkRect::MakeWH(SkIntToScalar(this->width()), 729 SkRect bbox = SkRect::MakeWH(SkIntToScalar(this->width()),
779 SkIntToScalar(this->height())); 730 SkIntToScalar(this->height()));
780 SkMatrix inverse; 731 SkMatrix inverse;
781 if (!contentEntry->fState.fMatrix.invert(&inverse)) { 732 if (!contentEntry->fState.fMatrix.invert(&inverse)) {
782 return; 733 return;
783 } 734 }
784 inverse.mapRect(&bbox); 735 inverse.mapRect(&bbox);
(...skipping 649 matching lines...) Expand 10 before | Expand all | Expand 10 after
1434 1385
1435 std::unique_ptr<SkStreamAsset> SkPDFDevice::content() const { 1386 std::unique_ptr<SkStreamAsset> SkPDFDevice::content() const {
1436 SkDynamicMemoryWStream buffer; 1387 SkDynamicMemoryWStream buffer;
1437 this->writeContent(&buffer); 1388 this->writeContent(&buffer);
1438 return std::unique_ptr<SkStreamAsset>( 1389 return std::unique_ptr<SkStreamAsset>(
1439 buffer.bytesWritten() > 0 1390 buffer.bytesWritten() > 0
1440 ? buffer.detachAsStream() 1391 ? buffer.detachAsStream()
1441 : new SkMemoryStream); 1392 : new SkMemoryStream);
1442 } 1393 }
1443 1394
1444 void SkPDFDevice::copyContentEntriesToData(ContentEntry* entry,
1445 SkWStream* data) const {
1446 // TODO(ctguil): For margins, I'm not sure fExistingClipStack/Region is the
1447 // right thing to pass here.
1448 GraphicStackState gsState(fExistingClipStack, fExistingClipRegion, data);
1449 while (entry != nullptr) {
1450 SkPoint translation;
1451 translation.iset(this->getOrigin());
1452 translation.negate();
1453 gsState.updateClip(entry->fState.fClipStack, entry->fState.fClipRegion,
1454 translation);
1455 gsState.updateMatrix(entry->fState.fMatrix);
1456 gsState.updateDrawingState(entry->fState);
1457
1458 entry->fContent.writeToStream(data);
1459 entry = entry->fNext.get();
1460 }
1461 gsState.drainStack();
1462 }
1463
1464 void SkPDFDevice::writeContent(SkWStream* out) const { 1395 void SkPDFDevice::writeContent(SkWStream* out) const {
1465 if (fInitialTransform.getType() != SkMatrix::kIdentity_Mask) { 1396 if (fInitialTransform.getType() != SkMatrix::kIdentity_Mask) {
1466 SkPDFUtils::AppendTransform(fInitialTransform, out); 1397 SkPDFUtils::AppendTransform(fInitialTransform, out);
1467 } 1398 }
1468 1399
1469 // If the content area is the entire page, then we don't need to clip 1400 // If the content area is the entire page, then we don't need to clip
1470 // the content area (PDF area clips to the page size). Otherwise, 1401 // the content area (PDF area clips to the page size). Otherwise,
1471 // we have to clip to the content area; we've already applied the 1402 // we have to clip to the content area; we've already applied the
1472 // initial transform, so just clip to the device size. 1403 // initial transform, so just clip to the device size.
1473 if (fPageSize != fContentSize) { 1404 if (fPageSize != fContentSize) {
1474 SkRect r = SkRect::MakeWH(SkIntToScalar(this->width()), 1405 SkRect r = SkRect::MakeWH(SkIntToScalar(this->width()),
1475 SkIntToScalar(this->height())); 1406 SkIntToScalar(this->height()));
1476 emit_clip(nullptr, &r, out); 1407 emit_clip(nullptr, &r, out);
1477 } 1408 }
1478 1409
1479 SkPDFDevice::copyContentEntriesToData(fContentEntries.get(), out); 1410 GraphicStackState gsState(fExistingClipStack, fExistingClipRegion, out);
1411 for (const auto& entry : fContentEntries) {
1412 SkPoint translation;
1413 translation.iset(this->getOrigin());
1414 translation.negate();
1415 gsState.updateClip(entry.fState.fClipStack, entry.fState.fClipRegion,
1416 translation);
1417 gsState.updateMatrix(entry.fState.fMatrix);
1418 gsState.updateDrawingState(entry.fState);
1419
1420 entry.fContent.writeToStream(out);
1421 }
1422 gsState.drainStack();
1480 } 1423 }
1481 1424
1482 /* Draws an inverse filled path by using Path Ops to compute the positive 1425 /* Draws an inverse filled path by using Path Ops to compute the positive
1483 * inverse using the current clip as the inverse bounds. 1426 * inverse using the current clip as the inverse bounds.
1484 * Return true if this was an inverse path and was properly handled, 1427 * Return true if this was an inverse path and was properly handled,
1485 * otherwise returns false and the normal drawing routine should continue, 1428 * otherwise returns false and the normal drawing routine should continue,
1486 * either as a (incorrect) fallback or because the path was not inverse 1429 * either as a (incorrect) fallback or because the path was not inverse
1487 * in the first place. 1430 * in the first place.
1488 */ 1431 */
1489 bool SkPDFDevice::handleInversePath(const SkDraw& d, const SkPath& origPath, 1432 bool SkPDFDevice::handleInversePath(const SkDraw& d, const SkPath& origPath,
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
1650 SkPDFUtils::DrawFormXObject(xObjectIndex, &content.entry()->fContent); 1593 SkPDFUtils::DrawFormXObject(xObjectIndex, &content.entry()->fContent);
1651 1594
1652 // Call makeNoSmaskGraphicState() instead of 1595 // Call makeNoSmaskGraphicState() instead of
1653 // SkPDFGraphicState::MakeNoSmaskGraphicState so that the canon 1596 // SkPDFGraphicState::MakeNoSmaskGraphicState so that the canon
1654 // can deduplicate. 1597 // can deduplicate.
1655 sMaskGS = fDocument->canon()->makeNoSmaskGraphicState(); 1598 sMaskGS = fDocument->canon()->makeNoSmaskGraphicState();
1656 SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()), 1599 SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
1657 &content.entry()->fContent); 1600 &content.entry()->fContent);
1658 } 1601 }
1659 1602
1660 ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack, 1603 SkPDFDevice::ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* cli pStack,
1661 const SkRegion& clipRegion, 1604 const SkRegion& clipRegion,
1662 const SkMatrix& matrix, 1605 const SkMatrix& matrix,
1663 const SkPaint& paint, 1606 const SkPaint& paint,
1664 bool hasText, 1607 bool hasText,
1665 SkPDFFormXObject** dst) { 1608 SkPDFFormXObject** dst) {
1666 *dst = nullptr; 1609 *dst = nullptr;
1667 if (clipRegion.isEmpty()) { 1610 if (clipRegion.isEmpty()) {
1668 return nullptr; 1611 return nullptr;
1669 } 1612 }
1670 1613
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1713 } 1656 }
1714 } 1657 }
1715 // TODO(vandebo): Figure out how/if we can handle the following modes: 1658 // TODO(vandebo): Figure out how/if we can handle the following modes:
1716 // Xor, Plus. 1659 // Xor, Plus.
1717 1660
1718 // Dst xfer mode doesn't draw source at all. 1661 // Dst xfer mode doesn't draw source at all.
1719 if (xfermode == SkXfermode::kDst_Mode) { 1662 if (xfermode == SkXfermode::kDst_Mode) {
1720 return nullptr; 1663 return nullptr;
1721 } 1664 }
1722 1665
1723 ContentEntry* entry; 1666 SkPDFDevice::ContentEntry* entry;
1724 SkAutoTDelete<ContentEntry> newEntry; 1667 if (fContentEntries.back() && fContentEntries.back()->fContent.getOffset() = = 0) {
1725 1668 entry = fContentEntries.back();
1726 if (fLastContentEntry && fLastContentEntry->fContent.getOffset() == 0) { 1669 } else if (xfermode != SkXfermode::kDstOver_Mode) {
1727 entry = fLastContentEntry; 1670 entry = fContentEntries.emplace_back();
1728 } else { 1671 } else {
1729 newEntry.reset(new ContentEntry); 1672 entry = fContentEntries.emplace_front();
1730 entry = newEntry.get();
1731 } 1673 }
1732
1733 populateGraphicStateEntryFromPaint(matrix, *clipStack, clipRegion, paint, 1674 populateGraphicStateEntryFromPaint(matrix, *clipStack, clipRegion, paint,
1734 hasText, &entry->fState); 1675 hasText, &entry->fState);
1735 if (fLastContentEntry && xfermode != SkXfermode::kDstOver_Mode &&
1736 entry->fState.compareInitialState(fLastContentEntry->fState)) {
1737 return fLastContentEntry;
1738 }
1739
1740 if (!fLastContentEntry) {
1741 fContentEntries.reset(entry);
1742 fLastContentEntry = entry;
1743 } else if (xfermode == SkXfermode::kDstOver_Mode) {
1744 entry->fNext.reset(fContentEntries.release());
1745 fContentEntries.reset(entry);
1746 } else {
1747 fLastContentEntry->fNext.reset(entry);
1748 fLastContentEntry = entry;
1749 }
1750 newEntry.release();
1751 return entry; 1676 return entry;
1752 } 1677 }
1753 1678
1754 void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode, 1679 void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode,
1755 SkPDFFormXObject* dst, 1680 SkPDFFormXObject* dst,
1756 SkPath* shape) { 1681 SkPath* shape) {
1757 if (xfermode != SkXfermode::kClear_Mode && 1682 if (xfermode != SkXfermode::kClear_Mode &&
1758 xfermode != SkXfermode::kSrc_Mode && 1683 xfermode != SkXfermode::kSrc_Mode &&
1759 xfermode != SkXfermode::kDstOver_Mode && 1684 xfermode != SkXfermode::kDstOver_Mode &&
1760 xfermode != SkXfermode::kSrcIn_Mode && 1685 xfermode != SkXfermode::kSrcIn_Mode &&
1761 xfermode != SkXfermode::kDstIn_Mode && 1686 xfermode != SkXfermode::kDstIn_Mode &&
1762 xfermode != SkXfermode::kSrcOut_Mode && 1687 xfermode != SkXfermode::kSrcOut_Mode &&
1763 xfermode != SkXfermode::kDstOut_Mode && 1688 xfermode != SkXfermode::kDstOut_Mode &&
1764 xfermode != SkXfermode::kSrcATop_Mode && 1689 xfermode != SkXfermode::kSrcATop_Mode &&
1765 xfermode != SkXfermode::kDstATop_Mode && 1690 xfermode != SkXfermode::kDstATop_Mode &&
1766 xfermode != SkXfermode::kModulate_Mode) { 1691 xfermode != SkXfermode::kModulate_Mode) {
1767 SkASSERT(!dst); 1692 SkASSERT(!dst);
1768 return; 1693 return;
1769 } 1694 }
1770 if (xfermode == SkXfermode::kDstOver_Mode) { 1695 if (xfermode == SkXfermode::kDstOver_Mode) {
1771 SkASSERT(!dst); 1696 SkASSERT(!dst);
1772 if (fContentEntries->fContent.getOffset() == 0) { 1697 if (fContentEntries.front()->fContent.getOffset() == 0) {
1773 // For DstOver, an empty content entry was inserted before the rest 1698 // For DstOver, an empty content entry was inserted before the rest
1774 // of the content entries. If nothing was drawn, it needs to be 1699 // of the content entries. If nothing was drawn, it needs to be
1775 // removed. 1700 // removed.
1776 fContentEntries.reset(fContentEntries->fNext.release()); 1701 fContentEntries.pop_front();
1777 } 1702 }
1778 return; 1703 return;
1779 } 1704 }
1780 if (!dst) { 1705 if (!dst) {
1781 SkASSERT(xfermode == SkXfermode::kSrc_Mode || 1706 SkASSERT(xfermode == SkXfermode::kSrc_Mode ||
1782 xfermode == SkXfermode::kSrcOut_Mode); 1707 xfermode == SkXfermode::kSrcOut_Mode);
1783 return; 1708 return;
1784 } 1709 }
1785 1710
1786 SkASSERT(dst); 1711 SkASSERT(dst);
1787 SkASSERT(!fContentEntries->fNext.get()); 1712 SkASSERT(fContentEntries.count() == 1);
1788 // Changing the current content into a form-xobject will destroy the clip 1713 // Changing the current content into a form-xobject will destroy the clip
1789 // objects which is fine since the xobject will already be clipped. However 1714 // objects which is fine since the xobject will already be clipped. However
1790 // if source has shape, we need to clip it too, so a copy of the clip is 1715 // if source has shape, we need to clip it too, so a copy of the clip is
1791 // saved. 1716 // saved.
1792 SkClipStack clipStack = fContentEntries->fState.fClipStack; 1717
1793 SkRegion clipRegion = fContentEntries->fState.fClipRegion; 1718 SkClipStack clipStack = fContentEntries.front()->fState.fClipStack;
1719 SkRegion clipRegion = fContentEntries.front()->fState.fClipRegion;
1794 1720
1795 SkMatrix identity; 1721 SkMatrix identity;
1796 identity.reset(); 1722 identity.reset();
1797 SkPaint stockPaint; 1723 SkPaint stockPaint;
1798 1724
1799 sk_sp<SkPDFFormXObject> srcFormXObject; 1725 sk_sp<SkPDFFormXObject> srcFormXObject;
1800 if (isContentEmpty()) { 1726 if (isContentEmpty()) {
1801 // If nothing was drawn and there's no shape, then the draw was a 1727 // If nothing was drawn and there's no shape, then the draw was a
1802 // no-op, but dst needs to be restored for that to be true. 1728 // no-op, but dst needs to be restored for that to be true.
1803 // If there is shape, then an empty source with Src, SrcIn, SrcOut, 1729 // If there is shape, then an empty source with Src, SrcIn, SrcOut,
1804 // DstIn, DstAtop or Modulate reduces to Clear and DstOut or SrcAtop 1730 // DstIn, DstAtop or Modulate reduces to Clear and DstOut or SrcAtop
1805 // reduces to Dst. 1731 // reduces to Dst.
1806 if (shape == nullptr || xfermode == SkXfermode::kDstOut_Mode || 1732 if (shape == nullptr || xfermode == SkXfermode::kDstOut_Mode ||
1807 xfermode == SkXfermode::kSrcATop_Mode) { 1733 xfermode == SkXfermode::kSrcATop_Mode) {
1808 ScopedContentEntry content(this, &fExistingClipStack, 1734 ScopedContentEntry content(this, &fExistingClipStack,
1809 fExistingClipRegion, identity, 1735 fExistingClipRegion, identity,
1810 stockPaint); 1736 stockPaint);
1811 SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst), 1737 SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst),
1812 &content.entry()->fContent); 1738 &content.entry()->fContent);
1813 return; 1739 return;
1814 } else { 1740 } else {
1815 xfermode = SkXfermode::kClear_Mode; 1741 xfermode = SkXfermode::kClear_Mode;
1816 } 1742 }
1817 } else { 1743 } else {
1818 SkASSERT(!fContentEntries->fNext.get()); 1744 SkASSERT(fContentEntries.count() == 1);
1819 srcFormXObject.reset(createFormXObjectFromDevice()); 1745 srcFormXObject.reset(createFormXObjectFromDevice());
1820 } 1746 }
1821 1747
1822 // TODO(vandebo) srcFormXObject may contain alpha, but here we want it 1748 // TODO(vandebo) srcFormXObject may contain alpha, but here we want it
1823 // without alpha. 1749 // without alpha.
1824 if (xfermode == SkXfermode::kSrcATop_Mode) { 1750 if (xfermode == SkXfermode::kSrcATop_Mode) {
1825 // TODO(vandebo): In order to properly support SrcATop we have to track 1751 // TODO(vandebo): In order to properly support SrcATop we have to track
1826 // the shape of what's been drawn at all times. It's the intersection of 1752 // the shape of what's been drawn at all times. It's the intersection of
1827 // the non-transparent parts of the device and the outlines (shape) of 1753 // the non-transparent parts of the device and the outlines (shape) of
1828 // all images and devices drawn. 1754 // all images and devices drawn.
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
1898 SkXfermode::kSrcOver_Mode, false); 1824 SkXfermode::kSrcOver_Mode, false);
1899 mode = SkXfermode::kMultiply_Mode; 1825 mode = SkXfermode::kMultiply_Mode;
1900 } 1826 }
1901 drawFormXObjectWithMask(addXObjectResource(dst), srcFormXObject.get(), 1827 drawFormXObjectWithMask(addXObjectResource(dst), srcFormXObject.get(),
1902 &fExistingClipStack, fExistingClipRegion, mode, 1828 &fExistingClipStack, fExistingClipRegion, mode,
1903 xfermode == SkXfermode::kDstOut_Mode); 1829 xfermode == SkXfermode::kDstOut_Mode);
1904 } 1830 }
1905 } 1831 }
1906 1832
1907 bool SkPDFDevice::isContentEmpty() { 1833 bool SkPDFDevice::isContentEmpty() {
1908 if (!fContentEntries || fContentEntries->fContent.getOffset() == 0) { 1834 if (!fContentEntries.front() || fContentEntries.front()->fContent.getOffset( ) == 0) {
1909 SkASSERT(!fContentEntries || !fContentEntries->fNext.get()); 1835 SkASSERT(fContentEntries.count() <= 1);
1910 return true; 1836 return true;
1911 } 1837 }
1912 return false; 1838 return false;
1913 } 1839 }
1914 1840
1915 void SkPDFDevice::populateGraphicStateEntryFromPaint( 1841 void SkPDFDevice::populateGraphicStateEntryFromPaint(
1916 const SkMatrix& matrix, 1842 const SkMatrix& matrix,
1917 const SkClipStack& clipStack, 1843 const SkClipStack& clipStack,
1918 const SkRegion& clipRegion, 1844 const SkRegion& clipRegion,
1919 const SkPaint& paint, 1845 const SkPaint& paint,
1920 bool hasText, 1846 bool hasText,
1921 GraphicStateEntry* entry) { 1847 SkPDFDevice::GraphicStateEntry* entry) {
1922 NOT_IMPLEMENTED(paint.getPathEffect() != nullptr, false); 1848 NOT_IMPLEMENTED(paint.getPathEffect() != nullptr, false);
1923 NOT_IMPLEMENTED(paint.getMaskFilter() != nullptr, false); 1849 NOT_IMPLEMENTED(paint.getMaskFilter() != nullptr, false);
1924 NOT_IMPLEMENTED(paint.getColorFilter() != nullptr, false); 1850 NOT_IMPLEMENTED(paint.getColorFilter() != nullptr, false);
1925 1851
1926 entry->fMatrix = matrix; 1852 entry->fMatrix = matrix;
1927 entry->fClipStack = clipStack; 1853 entry->fClipStack = clipStack;
1928 entry->fClipRegion = clipRegion; 1854 entry->fClipRegion = clipRegion;
1929 entry->fColor = SkColorSetA(paint.getColor(), 0xFF); 1855 entry->fColor = SkColorSetA(paint.getColor(), 0xFF);
1930 entry->fShaderIndex = -1; 1856 entry->fShaderIndex = -1;
1931 1857
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
2020 int result = fXObjectResources.find(xObject); 1946 int result = fXObjectResources.find(xObject);
2021 if (result < 0) { 1947 if (result < 0) {
2022 result = fXObjectResources.count(); 1948 result = fXObjectResources.count();
2023 fXObjectResources.push(xObject); 1949 fXObjectResources.push(xObject);
2024 xObject->ref(); 1950 xObject->ref();
2025 } 1951 }
2026 return result; 1952 return result;
2027 } 1953 }
2028 1954
2029 void SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID, 1955 void SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID,
2030 ContentEntry* contentEntry) { 1956 SkPDFDevice::ContentEntry* contentEntry) {
2031 SkTypeface* typeface = paint.getTypeface(); 1957 SkTypeface* typeface = paint.getTypeface();
2032 if (contentEntry->fState.fFont == nullptr || 1958 if (contentEntry->fState.fFont == nullptr ||
2033 contentEntry->fState.fTextSize != paint.getTextSize() || 1959 contentEntry->fState.fTextSize != paint.getTextSize() ||
2034 !contentEntry->fState.fFont->hasGlyph(glyphID)) { 1960 !contentEntry->fState.fFont->hasGlyph(glyphID)) {
2035 int fontIndex = getFontResourceIndex(typeface, glyphID); 1961 int fontIndex = getFontResourceIndex(typeface, glyphID);
2036 contentEntry->fContent.writeText("/"); 1962 contentEntry->fContent.writeText("/");
2037 contentEntry->fContent.writeText(SkPDFResourceDict::getResourceName( 1963 contentEntry->fContent.writeText(SkPDFResourceDict::getResourceName(
2038 SkPDFResourceDict::kFont_ResourceType, 1964 SkPDFResourceDict::kFont_ResourceType,
2039 fontIndex).c_str()); 1965 fontIndex).c_str());
2040 contentEntry->fContent.writeText(" "); 1966 contentEntry->fContent.writeText(" ");
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
2213 if (!pdfimage) { 2139 if (!pdfimage) {
2214 return; 2140 return;
2215 } 2141 }
2216 fDocument->serialize(pdfimage); // serialize images early. 2142 fDocument->serialize(pdfimage); // serialize images early.
2217 fDocument->canon()->addPDFBitmap(key, pdfimage); 2143 fDocument->canon()->addPDFBitmap(key, pdfimage);
2218 } 2144 }
2219 // TODO(halcanary): addXObjectResource() should take a sk_sp<SkPDFObject> 2145 // TODO(halcanary): addXObjectResource() should take a sk_sp<SkPDFObject>
2220 SkPDFUtils::DrawFormXObject(this->addXObjectResource(pdfimage.get()), 2146 SkPDFUtils::DrawFormXObject(this->addXObjectResource(pdfimage.get()),
2221 &content.entry()->fContent); 2147 &content.entry()->fContent);
2222 } 2148 }
OLDNEW
« no previous file with comments | « src/pdf/SkPDFDevice.h ('k') | src/pdf/SkSinglyLinkedList.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698