1 2 /* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10 #include "SkPDFDevice.h" 11 12 #include "SkColor.h" 13 #include "SkClipStack.h" 14 #include "SkData.h" 15 #include "SkDraw.h" 16 #include "SkGlyphCache.h" 17 #include "SkPaint.h" 18 #include "SkPath.h" 19 #include "SkPDFFont.h" 20 #include "SkPDFFormXObject.h" 21 #include "SkPDFGraphicState.h" 22 #include "SkPDFImage.h" 23 #include "SkPDFShader.h" 24 #include "SkPDFStream.h" 25 #include "SkPDFTypes.h" 26 #include "SkPDFUtils.h" 27 #include "SkRect.h" 28 #include "SkString.h" 29 #include "SkTextFormatParams.h" 30 #include "SkTypeface.h" 31 #include "SkTypes.h" 32 33 // Utility functions 34 35 static void emit_pdf_color(SkColor color, SkWStream* result) { 36 SkASSERT(SkColorGetA(color) == 0xFF); // We handle alpha elsewhere. 37 SkScalar colorMax = SkIntToScalar(0xFF); 38 SkPDFScalar::Append( 39 SkScalarDiv(SkIntToScalar(SkColorGetR(color)), colorMax), result); 40 result->writeText(" "); 41 SkPDFScalar::Append( 42 SkScalarDiv(SkIntToScalar(SkColorGetG(color)), colorMax), result); 43 result->writeText(" "); 44 SkPDFScalar::Append( 45 SkScalarDiv(SkIntToScalar(SkColorGetB(color)), colorMax), result); 46 result->writeText(" "); 47 } 48 49 static SkPaint calculate_text_paint(const SkPaint& paint) { 50 SkPaint result = paint; 51 if (result.isFakeBoldText()) { 52 SkScalar fakeBoldScale = SkScalarInterpFunc(result.getTextSize(), 53 kStdFakeBoldInterpKeys, 54 kStdFakeBoldInterpValues, 55 kStdFakeBoldInterpLength); 56 SkScalar width = SkScalarMul(result.getTextSize(), fakeBoldScale); 57 if (result.getStyle() == SkPaint::kFill_Style) { 58 result.setStyle(SkPaint::kStrokeAndFill_Style); 59 } else { 60 width += result.getStrokeWidth(); 61 } 62 result.setStrokeWidth(width); 63 } 64 return result; 65 } 66 67 // Stolen from measure_text in SkDraw.cpp and then tweaked. 68 static void align_text(SkDrawCacheProc glyphCacheProc, const SkPaint& paint, 69 const uint16_t* glyphs, size_t len, 70 SkScalar* x, SkScalar* y) { 71 if (paint.getTextAlign() == SkPaint::kLeft_Align) { 72 return; 73 } 74 75 SkMatrix ident; 76 ident.reset(); 77 SkAutoGlyphCache autoCache(paint, &ident); 78 SkGlyphCache* cache = autoCache.getCache(); 79 80 const char* start = reinterpret_cast<const char*>(glyphs); 81 const char* stop = reinterpret_cast<const char*>(glyphs + len); 82 SkFixed xAdv = 0, yAdv = 0; 83 84 // TODO(vandebo): This probably needs to take kerning into account. 85 while (start < stop) { 86 const SkGlyph& glyph = glyphCacheProc(cache, &start, 0, 0); 87 xAdv += glyph.fAdvanceX; 88 yAdv += glyph.fAdvanceY; 89 }; 90 if (paint.getTextAlign() == SkPaint::kLeft_Align) { 91 return; 92 } 93 94 SkScalar xAdj = SkFixedToScalar(xAdv); 95 SkScalar yAdj = SkFixedToScalar(yAdv); 96 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 97 xAdj = SkScalarHalf(xAdj); 98 yAdj = SkScalarHalf(yAdj); 99 } 100 *x = *x - xAdj; 101 *y = *y - yAdj; 102 } 103 104 static void set_text_transform(SkScalar x, SkScalar y, SkScalar textSkewX, 105 SkWStream* content) { 106 // Flip the text about the x-axis to account for origin swap and include 107 // the passed parameters. 108 content->writeText("1 0 "); 109 SkPDFScalar::Append(0 - textSkewX, content); 110 content->writeText(" -1 "); 111 SkPDFScalar::Append(x, content); 112 content->writeText(" "); 113 SkPDFScalar::Append(y, content); 114 content->writeText(" Tm\n"); 115 } 116 117 // It is important to not confuse GraphicStateEntry with SkPDFGraphicState, the 118 // later being our representation of an object in the PDF file. 119 struct GraphicStateEntry { 120 GraphicStateEntry(); 121 122 // Compare the fields we care about when setting up a new content entry. 123 bool compareInitialState(const GraphicStateEntry& b); 124 125 SkMatrix fMatrix; 126 // We can't do set operations on Paths, though PDF natively supports 127 // intersect. If the clip stack does anything other than intersect, 128 // we have to fall back to the region. Treat fClipStack as authoritative. 129 // See http://code.google.com/p/skia/issues/detail?id=221 130 SkClipStack fClipStack; 131 SkRegion fClipRegion; 132 133 // When emitting the content entry, we will ensure the graphic state 134 // is set to these values first. 135 SkColor fColor; 136 SkScalar fTextScaleX; // Zero means we don't care what the value is. 137 SkPaint::Style fTextFill; // Only if TextScaleX is non-zero. 138 int fShaderIndex; 139 int fGraphicStateIndex; 140 141 // We may change the font (i.e. for Type1 support) within a 142 // ContentEntry. This is the one currently in effect, or NULL if none. 143 SkPDFFont* fFont; 144 // In PDF, text size has no default value. It is only valid if fFont is 145 // not NULL. 146 SkScalar fTextSize; 147 }; 148 149 GraphicStateEntry::GraphicStateEntry() : fColor(SK_ColorBLACK), 150 fTextScaleX(SK_Scalar1), 151 fTextFill(SkPaint::kFill_Style), 152 fShaderIndex(-1), 153 fGraphicStateIndex(-1), 154 fFont(NULL), 155 fTextSize(SK_ScalarNaN) { 156 fMatrix.reset(); 157 } 158 159 bool GraphicStateEntry::compareInitialState(const GraphicStateEntry& b) { 160 return fColor == b.fColor && 161 fShaderIndex == b.fShaderIndex && 162 fGraphicStateIndex == b.fGraphicStateIndex && 163 fMatrix == b.fMatrix && 164 fClipStack == b.fClipStack && 165 (fTextScaleX == 0 || 166 b.fTextScaleX == 0 || 167 (fTextScaleX == b.fTextScaleX && fTextFill == b.fTextFill)); 168 } 169 170 class GraphicStackState { 171 public: 172 GraphicStackState(const SkClipStack& existingClipStack, 173 const SkRegion& existingClipRegion, 174 SkWStream* contentStream) 175 : fStackDepth(0), 176 fContentStream(contentStream) { 177 fEntries[0].fClipStack = existingClipStack; 178 fEntries[0].fClipRegion = existingClipRegion; 179 } 180 181 void updateClip(const SkClipStack& clipStack, const SkRegion& clipRegion, 182 const SkPoint& translation); 183 void updateMatrix(const SkMatrix& matrix); 184 void updateDrawingState(const GraphicStateEntry& state); 185 186 void drainStack(); 187 188 private: 189 void push(); 190 void pop(); 191 GraphicStateEntry* currentEntry() { return &fEntries[fStackDepth]; } 192 193 // Conservative limit on save depth, see impl. notes in PDF 1.4 spec. 194 static const int kMaxStackDepth = 12; 195 GraphicStateEntry fEntries[kMaxStackDepth + 1]; 196 int fStackDepth; 197 SkWStream* fContentStream; 198 }; 199 200 void GraphicStackState::drainStack() { 201 while (fStackDepth) { 202 pop(); 203 } 204 } 205 206 void GraphicStackState::push() { 207 SkASSERT(fStackDepth < kMaxStackDepth); 208 fContentStream->writeText("q\n"); 209 fStackDepth++; 210 fEntries[fStackDepth] = fEntries[fStackDepth - 1]; 211 } 212 213 void GraphicStackState::pop() { 214 SkASSERT(fStackDepth > 0); 215 fContentStream->writeText("Q\n"); 216 fStackDepth--; 217 } 218 219 // This function initializes iter to be an interator on the "stack" argument 220 // and then skips over the leading entries as specified in prefix. It requires 221 // and asserts that "prefix" will be a prefix to "stack." 222 static void skip_clip_stack_prefix(const SkClipStack& prefix, 223 const SkClipStack& stack, 224 SkClipStack::B2FIter* iter) { 225 SkClipStack::B2FIter prefixIter(prefix); 226 iter->reset(stack); 227 228 const SkClipStack::B2FIter::Clip* prefixEntry; 229 const SkClipStack::B2FIter::Clip* iterEntry; 230 231 int count = 0; 232 for (prefixEntry = prefixIter.next(); prefixEntry; 233 prefixEntry = prefixIter.next(), count++) { 234 iterEntry = iter->next(); 235 SkASSERT(iterEntry); 236 // Because of SkClipStack does internal intersection, the last clip 237 // entry may differ. 238 if (*prefixEntry != *iterEntry) { 239 SkASSERT(prefixEntry->fOp == SkRegion::kIntersect_Op); 240 SkASSERT(iterEntry->fOp == SkRegion::kIntersect_Op); 241 SkASSERT((iterEntry->fRect == NULL) == 242 (prefixEntry->fRect == NULL)); 243 SkASSERT((iterEntry->fPath == NULL) == 244 (prefixEntry->fPath == NULL)); 245 // We need to back up the iterator by one but don't have that 246 // function, so reset and go forward by one less. 247 iter->reset(stack); 248 for (int i = 0; i < count; i++) { 249 iter->next(); 250 } 251 prefixEntry = prefixIter.next(); 252 break; 253 } 254 } 255 256 SkASSERT(prefixEntry == NULL); 257 } 258 259 static void emit_clip(SkPath* clipPath, SkRect* clipRect, 260 SkWStream* contentStream) { 261 SkASSERT(clipPath || clipRect); 262 263 SkPath::FillType clipFill; 264 if (clipPath) { 265 SkPDFUtils::EmitPath(*clipPath, contentStream); 266 clipFill = clipPath->getFillType(); 267 } else { 268 SkPDFUtils::AppendRectangle(*clipRect, contentStream); 269 clipFill = SkPath::kWinding_FillType; 270 } 271 272 NOT_IMPLEMENTED(clipFill == SkPath::kInverseEvenOdd_FillType, false); 273 NOT_IMPLEMENTED(clipFill == SkPath::kInverseWinding_FillType, false); 274 if (clipFill == SkPath::kEvenOdd_FillType) { 275 contentStream->writeText("W* n\n"); 276 } else { 277 contentStream->writeText("W n\n"); 278 } 279 } 280 281 // TODO(vandebo): Take advantage of SkClipStack::getSaveCount(), the PDF 282 // graphic state stack, and the fact that we can know all the clips used 283 // on the page to optimize this. 284 void GraphicStackState::updateClip(const SkClipStack& clipStack, 285 const SkRegion& clipRegion, 286 const SkPoint& translation) { 287 if (clipStack == currentEntry()->fClipStack) { 288 return; 289 } 290 291 while (fStackDepth > 0) { 292 pop(); 293 if (clipStack == currentEntry()->fClipStack) { 294 return; 295 } 296 } 297 push(); 298 299 // gsState->initialEntry()->fClipStack/Region specifies the clip that has 300 // already been applied. (If this is a top level device, then it specifies 301 // a clip to the content area. If this is a layer, then it specifies 302 // the clip in effect when the layer was created.) There's no need to 303 // reapply that clip; SKCanvas's SkDrawIter will draw anything outside the 304 // initial clip on the parent layer. (This means there's a bug if the user 305 // expands the clip and then uses any xfer mode that uses dst: 306 // http://code.google.com/p/skia/issues/detail?id=228 ) 307 SkClipStack::B2FIter iter; 308 skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter); 309 310 // If the clip stack does anything other than intersect or if it uses 311 // an inverse fill type, we have to fall back to the clip region. 312 bool needRegion = false; 313 const SkClipStack::B2FIter::Clip* clipEntry; 314 for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) { 315 if (clipEntry->fOp != SkRegion::kIntersect_Op || 316 (clipEntry->fPath && clipEntry->fPath->isInverseFillType())) { 317 needRegion = true; 318 break; 319 } 320 } 321 322 if (needRegion) { 323 SkPath clipPath; 324 SkAssertResult(clipRegion.getBoundaryPath(&clipPath)); 325 emit_clip(&clipPath, NULL, fContentStream); 326 } else { 327 skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter); 328 SkMatrix transform; 329 transform.setTranslate(translation.fX, translation.fY); 330 const SkClipStack::B2FIter::Clip* clipEntry; 331 for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) { 332 SkASSERT(clipEntry->fOp == SkRegion::kIntersect_Op); 333 if (clipEntry->fRect) { 334 SkRect translatedClip; 335 transform.mapRect(&translatedClip, *clipEntry->fRect); 336 emit_clip(NULL, &translatedClip, fContentStream); 337 } else if (clipEntry->fPath) { 338 SkPath translatedPath; 339 clipEntry->fPath->transform(transform, &translatedPath); 340 emit_clip(&translatedPath, NULL, fContentStream); 341 } else { 342 SkASSERT(false); 343 } 344 } 345 } 346 currentEntry()->fClipStack = clipStack; 347 currentEntry()->fClipRegion = clipRegion; 348 } 349 350 void GraphicStackState::updateMatrix(const SkMatrix& matrix) { 351 if (matrix == currentEntry()->fMatrix) { 352 return; 353 } 354 355 if (currentEntry()->fMatrix.getType() != SkMatrix::kIdentity_Mask) { 356 SkASSERT(fStackDepth > 0); 357 SkASSERT(fEntries[fStackDepth].fClipStack == 358 fEntries[fStackDepth -1].fClipStack); 359 pop(); 360 361 SkASSERT(currentEntry()->fMatrix.getType() == SkMatrix::kIdentity_Mask); 362 } 363 if (matrix.getType() == SkMatrix::kIdentity_Mask) { 364 return; 365 } 366 367 push(); 368 SkPDFUtils::AppendTransform(matrix, fContentStream); 369 currentEntry()->fMatrix = matrix; 370 } 371 372 void GraphicStackState::updateDrawingState(const GraphicStateEntry& state) { 373 // PDF treats a shader as a color, so we only set one or the other. 374 if (state.fShaderIndex >= 0) { 375 if (state.fShaderIndex != currentEntry()->fShaderIndex) { 376 fContentStream->writeText("/Pattern CS /Pattern cs /P"); 377 fContentStream->writeDecAsText(state.fShaderIndex); 378 fContentStream->writeText(" SCN /P"); 379 fContentStream->writeDecAsText(state.fShaderIndex); 380 fContentStream->writeText(" scn\n"); 381 currentEntry()->fShaderIndex = state.fShaderIndex; 382 } 383 } else { 384 if (state.fColor != currentEntry()->fColor || 385 currentEntry()->fShaderIndex >= 0) { 386 emit_pdf_color(state.fColor, fContentStream); 387 fContentStream->writeText("RG "); 388 emit_pdf_color(state.fColor, fContentStream); 389 fContentStream->writeText("rg\n"); 390 currentEntry()->fColor = state.fColor; 391 currentEntry()->fShaderIndex = -1; 392 } 393 } 394 395 if (state.fGraphicStateIndex != currentEntry()->fGraphicStateIndex) { 396 SkPDFUtils::ApplyGraphicState(state.fGraphicStateIndex, fContentStream); 397 currentEntry()->fGraphicStateIndex = state.fGraphicStateIndex; 398 } 399 400 if (state.fTextScaleX) { 401 if (state.fTextScaleX != currentEntry()->fTextScaleX) { 402 SkScalar pdfScale = SkScalarMul(state.fTextScaleX, 403 SkIntToScalar(100)); 404 SkPDFScalar::Append(pdfScale, fContentStream); 405 fContentStream->writeText(" Tz\n"); 406 currentEntry()->fTextScaleX = state.fTextScaleX; 407 } 408 if (state.fTextFill != currentEntry()->fTextFill) { 409 SK_COMPILE_ASSERT(SkPaint::kFill_Style == 0, enum_must_match_value); 410 SK_COMPILE_ASSERT(SkPaint::kStroke_Style == 1, 411 enum_must_match_value); 412 SK_COMPILE_ASSERT(SkPaint::kStrokeAndFill_Style == 2, 413 enum_must_match_value); 414 fContentStream->writeDecAsText(state.fTextFill); 415 fContentStream->writeText(" Tr\n"); 416 currentEntry()->fTextFill = state.fTextFill; 417 } 418 } 419 } 420 421 SkDevice* SkPDFDevice::onCreateCompatibleDevice(SkBitmap::Config config, 422 int width, int height, 423 bool isOpaque, 424 Usage usage) { 425 SkMatrix initialTransform; 426 initialTransform.reset(); 427 SkISize size = SkISize::Make(width, height); 428 return SkNEW_ARGS(SkPDFDevice, (size, size, initialTransform)); 429 } 430 431 432 struct ContentEntry { 433 GraphicStateEntry fState; 434 SkDynamicMemoryWStream fContent; 435 SkTScopedPtr<ContentEntry> fNext; 436 }; 437 438 // A helper class to automatically finish a ContentEntry at the end of a 439 // drawing method and maintain the state needed between set up and finish. 440 class ScopedContentEntry { 441 public: 442 ScopedContentEntry(SkPDFDevice* device, const SkDraw& draw, 443 const SkPaint& paint, bool hasText = false) 444 : fDevice(device), 445 fContentEntry(NULL), 446 fXfermode(SkXfermode::kSrcOver_Mode) { 447 init(draw.fClipStack, *draw.fClip, *draw.fMatrix, paint, hasText); 448 } 449 ScopedContentEntry(SkPDFDevice* device, const SkClipStack* clipStack, 450 const SkRegion& clipRegion, const SkMatrix& matrix, 451 const SkPaint& paint, bool hasText = false) 452 : fDevice(device), 453 fContentEntry(NULL), 454 fXfermode(SkXfermode::kSrcOver_Mode) { 455 init(clipStack, clipRegion, matrix, paint, hasText); 456 } 457 458 ~ScopedContentEntry() { 459 if (fContentEntry) { 460 fDevice->finishContentEntry(fXfermode, fDstFormXObject.get()); 461 } 462 } 463 464 ContentEntry* entry() { return fContentEntry; } 465 private: 466 SkPDFDevice* fDevice; 467 ContentEntry* fContentEntry; 468 SkXfermode::Mode fXfermode; 469 SkRefPtr<SkPDFFormXObject> fDstFormXObject; 470 471 void init(const SkClipStack* clipStack, const SkRegion& clipRegion, 472 const SkMatrix& matrix, const SkPaint& paint, bool hasText) { 473 if (paint.getXfermode()) { 474 paint.getXfermode()->asMode(&fXfermode); 475 } 476 fContentEntry = fDevice->setUpContentEntry(clipStack, clipRegion, 477 matrix, paint, hasText, 478 &fDstFormXObject); 479 } 480 }; 481 482 //////////////////////////////////////////////////////////////////////////////// 483 484 static inline SkBitmap makeContentBitmap(const SkISize& contentSize, 485 const SkMatrix* initialTransform) { 486 SkBitmap bitmap; 487 if (initialTransform) { 488 // Compute the size of the drawing area. 489 SkVector drawingSize; 490 SkMatrix inverse; 491 drawingSize.set(SkIntToScalar(contentSize.fWidth), 492 SkIntToScalar(contentSize.fHeight)); 493 initialTransform->invert(&inverse); 494 inverse.mapVectors(&drawingSize, 1); 495 SkISize size = SkSize::Make(drawingSize.fX, drawingSize.fY).toRound(); 496 bitmap.setConfig(SkBitmap::kNo_Config, abs(size.fWidth), 497 abs(size.fHeight)); 498 } else { 499 bitmap.setConfig(SkBitmap::kNo_Config, abs(contentSize.fWidth), 500 abs(contentSize.fHeight)); 501 } 502 503 return bitmap; 504 } 505 506 // TODO(vandebo) change pageSize to SkSize. 507 SkPDFDevice::SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize, 508 const SkMatrix& initialTransform) 509 : SkDevice(makeContentBitmap(contentSize, &initialTransform)), 510 fPageSize(pageSize), 511 fContentSize(contentSize), 512 fLastContentEntry(NULL), 513 fLastMarginContentEntry(NULL) { 514 // Skia generally uses the top left as the origin but PDF natively has the 515 // origin at the bottom left. This matrix corrects for that. But that only 516 // needs to be done once, we don't do it when layering. 517 fInitialTransform.setTranslate(0, SkIntToScalar(pageSize.fHeight)); 518 fInitialTransform.preScale(SK_Scalar1, -SK_Scalar1); 519 fInitialTransform.preConcat(initialTransform); 520 521 SkIRect existingClip = SkIRect::MakeWH(this->width(), this->height()); 522 fExistingClipRegion.setRect(existingClip); 523 524 this->init(); 525 } 526 527 // TODO(vandebo) change layerSize to SkSize. 528 SkPDFDevice::SkPDFDevice(const SkISize& layerSize, 529 const SkClipStack& existingClipStack, 530 const SkRegion& existingClipRegion) 531 : SkDevice(makeContentBitmap(layerSize, NULL)), 532 fPageSize(layerSize), 533 fContentSize(layerSize), 534 fExistingClipStack(existingClipStack), 535 fExistingClipRegion(existingClipRegion), 536 fLastContentEntry(NULL), 537 fLastMarginContentEntry(NULL) { 538 fInitialTransform.reset(); 539 this->init(); 540 } 541 542 SkPDFDevice::~SkPDFDevice() { 543 this->cleanUp(true); 544 } 545 546 void SkPDFDevice::init() { 547 fResourceDict = NULL; 548 fContentEntries.reset(); 549 fLastContentEntry = NULL; 550 fMarginContentEntries.reset(); 551 fLastMarginContentEntry = NULL; 552 fDrawingArea = kContent_DrawingArea; 553 if (fFontGlyphUsage == NULL) { 554 fFontGlyphUsage.reset(new SkPDFGlyphSetMap()); 555 } 556 } 557 558 void SkPDFDevice::cleanUp(bool clearFontUsage) { 559 fGraphicStateResources.unrefAll(); 560 fXObjectResources.unrefAll(); 561 fFontResources.unrefAll(); 562 fShaderResources.unrefAll(); 563 if (clearFontUsage) { 564 fFontGlyphUsage->reset(); 565 } 566 } 567 568 uint32_t SkPDFDevice::getDeviceCapabilities() { 569 return kVector_Capability; 570 } 571 572 void SkPDFDevice::clear(SkColor color) { 573 this->cleanUp(true); 574 this->init(); 575 576 SkPaint paint; 577 paint.setColor(color); 578 paint.setStyle(SkPaint::kFill_Style); 579 SkMatrix identity; 580 identity.reset(); 581 ScopedContentEntry content(this, &fExistingClipStack, fExistingClipRegion, 582 identity, paint); 583 internalDrawPaint(paint, content.entry()); 584 } 585 586 void SkPDFDevice::drawPaint(const SkDraw& d, const SkPaint& paint) { 587 SkPaint newPaint = paint; 588 newPaint.setStyle(SkPaint::kFill_Style); 589 ScopedContentEntry content(this, d, newPaint); 590 internalDrawPaint(newPaint, content.entry()); 591 } 592 593 void SkPDFDevice::internalDrawPaint(const SkPaint& paint, 594 ContentEntry* contentEntry) { 595 if (!contentEntry) { 596 return; 597 } 598 SkRect bbox = SkRect::MakeWH(SkIntToScalar(this->width()), 599 SkIntToScalar(this->height())); 600 SkMatrix totalTransform = fInitialTransform; 601 totalTransform.preConcat(contentEntry->fState.fMatrix); 602 SkMatrix inverse; 603 inverse.reset(); 604 totalTransform.invert(&inverse); 605 inverse.mapRect(&bbox); 606 607 SkPDFUtils::AppendRectangle(bbox, &contentEntry->fContent); 608 SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType, 609 &contentEntry->fContent); 610 } 611 612 void SkPDFDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode, 613 size_t count, const SkPoint* points, 614 const SkPaint& passedPaint) { 615 if (count == 0) { 616 return; 617 } 618 619 // SkDraw::drawPoints converts to multiple calls to fDevice->drawPath. 620 // We only use this when there's a path effect because of the overhead 621 // of multiple calls to setUpContentEntry it causes. 622 if (passedPaint.getPathEffect()) { 623 if (d.fClip->isEmpty()) { 624 return; 625 } 626 SkDraw pointDraw(d); 627 pointDraw.fDevice = this; 628 pointDraw.drawPoints(mode, count, points, passedPaint, true); 629 return; 630 } 631 632 const SkPaint* paint = &passedPaint; 633 SkPaint modifiedPaint; 634 635 if (mode == SkCanvas::kPoints_PointMode && 636 paint->getStrokeCap() != SkPaint::kRound_Cap) { 637 modifiedPaint = *paint; 638 paint = &modifiedPaint; 639 if (paint->getStrokeWidth()) { 640 // PDF won't draw a single point with square/butt caps because the 641 // orientation is ambiguous. Draw a rectangle instead. 642 modifiedPaint.setStyle(SkPaint::kFill_Style); 643 SkScalar strokeWidth = paint->getStrokeWidth(); 644 SkScalar halfStroke = SkScalarHalf(strokeWidth); 645 for (size_t i = 0; i < count; i++) { 646 SkRect r = SkRect::MakeXYWH(points[i].fX, points[i].fY, 0, 0); 647 r.inset(-halfStroke, -halfStroke); 648 drawRect(d, r, modifiedPaint); 649 } 650 return; 651 } else { 652 modifiedPaint.setStrokeCap(SkPaint::kRound_Cap); 653 } 654 } 655 656 ScopedContentEntry content(this, d, *paint); 657 if (!content.entry()) { 658 return; 659 } 660 661 switch (mode) { 662 case SkCanvas::kPolygon_PointMode: 663 SkPDFUtils::MoveTo(points[0].fX, points[0].fY, 664 &content.entry()->fContent); 665 for (size_t i = 1; i < count; i++) { 666 SkPDFUtils::AppendLine(points[i].fX, points[i].fY, 667 &content.entry()->fContent); 668 } 669 SkPDFUtils::StrokePath(&content.entry()->fContent); 670 break; 671 case SkCanvas::kLines_PointMode: 672 for (size_t i = 0; i < count/2; i++) { 673 SkPDFUtils::MoveTo(points[i * 2].fX, points[i * 2].fY, 674 &content.entry()->fContent); 675 SkPDFUtils::AppendLine(points[i * 2 + 1].fX, 676 points[i * 2 + 1].fY, 677 &content.entry()->fContent); 678 SkPDFUtils::StrokePath(&content.entry()->fContent); 679 } 680 break; 681 case SkCanvas::kPoints_PointMode: 682 SkASSERT(paint->getStrokeCap() == SkPaint::kRound_Cap); 683 for (size_t i = 0; i < count; i++) { 684 SkPDFUtils::MoveTo(points[i].fX, points[i].fY, 685 &content.entry()->fContent); 686 SkPDFUtils::ClosePath(&content.entry()->fContent); 687 SkPDFUtils::StrokePath(&content.entry()->fContent); 688 } 689 break; 690 default: 691 SkASSERT(false); 692 } 693 } 694 695 void SkPDFDevice::drawRect(const SkDraw& d, const SkRect& r, 696 const SkPaint& paint) { 697 if (paint.getPathEffect()) { 698 if (d.fClip->isEmpty()) { 699 return; 700 } 701 SkPath path; 702 path.addRect(r); 703 drawPath(d, path, paint, NULL, true); 704 return; 705 } 706 707 ScopedContentEntry content(this, d, paint); 708 if (!content.entry()) { 709 return; 710 } 711 SkPDFUtils::AppendRectangle(r, &content.entry()->fContent); 712 SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType, 713 &content.entry()->fContent); 714 } 715 716 void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& origPath, 717 const SkPaint& paint, const SkMatrix* prePathMatrix, 718 bool pathIsMutable) { 719 SkPath modifiedPath; 720 SkPath* pathPtr = const_cast<SkPath*>(&origPath); 721 722 SkMatrix matrix = *d.fMatrix; 723 if (prePathMatrix) { 724 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) { 725 if (!pathIsMutable) { 726 pathPtr = &modifiedPath; 727 pathIsMutable = true; 728 } 729 origPath.transform(*prePathMatrix, pathPtr); 730 } else { 731 if (!matrix.preConcat(*prePathMatrix)) { 732 return; 733 } 734 } 735 } 736 737 if (paint.getPathEffect()) { 738 if (d.fClip->isEmpty()) { 739 return; 740 } 741 if (!pathIsMutable) { 742 pathPtr = &modifiedPath; 743 pathIsMutable = true; 744 } 745 bool fill = paint.getFillPath(origPath, pathPtr); 746 747 SkPaint noEffectPaint(paint); 748 noEffectPaint.setPathEffect(NULL); 749 if (fill) { 750 noEffectPaint.setStyle(SkPaint::kFill_Style); 751 } else { 752 noEffectPaint.setStyle(SkPaint::kStroke_Style); 753 noEffectPaint.setStrokeWidth(0); 754 } 755 drawPath(d, *pathPtr, noEffectPaint, NULL, true); 756 return; 757 } 758 759 ScopedContentEntry content(this, d, paint); 760 if (!content.entry()) { 761 return; 762 } 763 SkPDFUtils::EmitPath(*pathPtr, &content.entry()->fContent); 764 SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(), 765 &content.entry()->fContent); 766 } 767 768 void SkPDFDevice::drawBitmap(const SkDraw& d, const SkBitmap& bitmap, 769 const SkIRect* srcRect, const SkMatrix& matrix, 770 const SkPaint& paint) { 771 if (d.fClip->isEmpty()) { 772 return; 773 } 774 775 SkMatrix transform = matrix; 776 transform.postConcat(*d.fMatrix); 777 internalDrawBitmap(transform, d.fClipStack, *d.fClip, bitmap, srcRect, 778 paint); 779 } 780 781 void SkPDFDevice::drawSprite(const SkDraw& d, const SkBitmap& bitmap, 782 int x, int y, const SkPaint& paint) { 783 if (d.fClip->isEmpty()) { 784 return; 785 } 786 787 SkMatrix matrix; 788 matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y)); 789 internalDrawBitmap(matrix, d.fClipStack, *d.fClip, bitmap, NULL, paint); 790 } 791 792 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, 793 SkScalar x, SkScalar y, const SkPaint& paint) { 794 SkPaint textPaint = calculate_text_paint(paint); 795 ScopedContentEntry content(this, d, textPaint, true); 796 if (!content.entry()) { 797 return; 798 } 799 800 // We want the text in glyph id encoding and a writable buffer, so we end 801 // up making a copy either way. 802 size_t numGlyphs = paint.textToGlyphs(text, len, NULL); 803 uint16_t* glyphIDs = reinterpret_cast<uint16_t*>( 804 sk_malloc_flags(numGlyphs * 2, SK_MALLOC_TEMP | SK_MALLOC_THROW)); 805 SkAutoFree autoFreeGlyphIDs(glyphIDs); 806 if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) { 807 paint.textToGlyphs(text, len, glyphIDs); 808 textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 809 } else { 810 SkASSERT((len & 1) == 0); 811 SkASSERT(len / 2 == numGlyphs); 812 memcpy(glyphIDs, text, len); 813 } 814 815 SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc(); 816 align_text(glyphCacheProc, textPaint, glyphIDs, numGlyphs, &x, &y); 817 content.entry()->fContent.writeText("BT\n"); 818 set_text_transform(x, y, textPaint.getTextSkewX(), 819 &content.entry()->fContent); 820 size_t consumedGlyphCount = 0; 821 while (numGlyphs > consumedGlyphCount) { 822 updateFont(textPaint, glyphIDs[consumedGlyphCount], content.entry()); 823 SkPDFFont* font = content.entry()->fState.fFont; 824 size_t availableGlyphs = 825 font->glyphsToPDFFontEncoding(glyphIDs + consumedGlyphCount, 826 numGlyphs - consumedGlyphCount); 827 fFontGlyphUsage->noteGlyphUsage(font, glyphIDs + consumedGlyphCount, 828 availableGlyphs); 829 SkString encodedString = 830 SkPDFString::FormatString(glyphIDs + consumedGlyphCount, 831 availableGlyphs, font->multiByteGlyphs()); 832 content.entry()->fContent.writeText(encodedString.c_str()); 833 consumedGlyphCount += availableGlyphs; 834 content.entry()->fContent.writeText(" Tj\n"); 835 } 836 content.entry()->fContent.writeText("ET\n"); 837 } 838 839 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, 840 const SkScalar pos[], SkScalar constY, 841 int scalarsPerPos, const SkPaint& paint) { 842 SkASSERT(1 == scalarsPerPos || 2 == scalarsPerPos); 843 SkPaint textPaint = calculate_text_paint(paint); 844 ScopedContentEntry content(this, d, textPaint, true); 845 if (!content.entry()) { 846 return; 847 } 848 849 // Make sure we have a glyph id encoding. 850 SkAutoFree glyphStorage; 851 uint16_t* glyphIDs; 852 size_t numGlyphs; 853 if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) { 854 numGlyphs = paint.textToGlyphs(text, len, NULL); 855 glyphIDs = reinterpret_cast<uint16_t*>(sk_malloc_flags( 856 numGlyphs * 2, SK_MALLOC_TEMP | SK_MALLOC_THROW)); 857 glyphStorage.set(glyphIDs); 858 paint.textToGlyphs(text, len, glyphIDs); 859 textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 860 } else { 861 SkASSERT((len & 1) == 0); 862 numGlyphs = len / 2; 863 glyphIDs = reinterpret_cast<uint16_t*>(const_cast<void*>((text))); 864 } 865 866 SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc(); 867 content.entry()->fContent.writeText("BT\n"); 868 updateFont(textPaint, glyphIDs[0], content.entry()); 869 for (size_t i = 0; i < numGlyphs; i++) { 870 SkPDFFont* font = content.entry()->fState.fFont; 871 uint16_t encodedValue = glyphIDs[i]; 872 if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) { 873 updateFont(textPaint, glyphIDs[i], content.entry()); 874 i--; 875 continue; 876 } 877 fFontGlyphUsage->noteGlyphUsage(font, &encodedValue, 1); 878 SkScalar x = pos[i * scalarsPerPos]; 879 SkScalar y = scalarsPerPos == 1 ? constY : pos[i * scalarsPerPos + 1]; 880 align_text(glyphCacheProc, textPaint, glyphIDs + i, 1, &x, &y); 881 set_text_transform(x, y, textPaint.getTextSkewX(), 882 &content.entry()->fContent); 883 SkString encodedString = 884 SkPDFString::FormatString(&encodedValue, 1, 885 font->multiByteGlyphs()); 886 content.entry()->fContent.writeText(encodedString.c_str()); 887 content.entry()->fContent.writeText(" Tj\n"); 888 } 889 content.entry()->fContent.writeText("ET\n"); 890 } 891 892 void SkPDFDevice::drawTextOnPath(const SkDraw& d, const void* text, size_t len, 893 const SkPath& path, const SkMatrix* matrix, 894 const SkPaint& paint) { 895 if (d.fClip->isEmpty()) { 896 return; 897 } 898 d.drawTextOnPath((const char*)text, len, path, matrix, paint); 899 } 900 901 void SkPDFDevice::drawVertices(const SkDraw& d, SkCanvas::VertexMode, 902 int vertexCount, const SkPoint verts[], 903 const SkPoint texs[], const SkColor colors[], 904 SkXfermode* xmode, const uint16_t indices[], 905 int indexCount, const SkPaint& paint) { 906 if (d.fClip->isEmpty()) { 907 return; 908 } 909 NOT_IMPLEMENTED("drawVerticies", true); 910 } 911 912 void SkPDFDevice::drawDevice(const SkDraw& d, SkDevice* device, int x, int y, 913 const SkPaint& paint) { 914 if ((device->getDeviceCapabilities() & kVector_Capability) == 0) { 915 // If we somehow get a raster device, do what our parent would do. 916 SkDevice::drawDevice(d, device, x, y, paint); 917 return; 918 } 919 920 // Assume that a vector capable device means that it's a PDF Device. 921 SkPDFDevice* pdfDevice = static_cast<SkPDFDevice*>(device); 922 if (pdfDevice->isContentEmpty()) { 923 return; 924 } 925 926 SkMatrix matrix; 927 matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y)); 928 ScopedContentEntry content(this, d.fClipStack, *d.fClip, matrix, paint); 929 if (!content.entry()) { 930 return; 931 } 932 933 SkPDFFormXObject* xobject = new SkPDFFormXObject(pdfDevice); 934 fXObjectResources.push(xobject); // Transfer reference. 935 SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1, 936 &content.entry()->fContent); 937 938 // Merge glyph sets from the drawn device. 939 fFontGlyphUsage->merge(pdfDevice->getFontGlyphUsage()); 940 } 941 942 ContentEntry* SkPDFDevice::getLastContentEntry() { 943 if (fDrawingArea == kContent_DrawingArea) { 944 return fLastContentEntry; 945 } else { 946 return fLastMarginContentEntry; 947 } 948 } 949 950 SkTScopedPtr<ContentEntry>* SkPDFDevice::getContentEntries() { 951 if (fDrawingArea == kContent_DrawingArea) { 952 return &fContentEntries; 953 } else { 954 return &fMarginContentEntries; 955 } 956 } 957 958 void SkPDFDevice::setLastContentEntry(ContentEntry* contentEntry) { 959 if (fDrawingArea == kContent_DrawingArea) { 960 fLastContentEntry = contentEntry; 961 } else { 962 fLastMarginContentEntry = contentEntry; 963 } 964 } 965 966 void SkPDFDevice::setDrawingArea(DrawingArea drawingArea) { 967 // A ScopedContentEntry only exists during the course of a draw call, so 968 // this can't be called while a ScopedContentEntry exists. 969 fDrawingArea = drawingArea; 970 } 971 972 SkPDFDict* SkPDFDevice::getResourceDict() { 973 if (fResourceDict.get() == NULL) { 974 fResourceDict = new SkPDFDict; 975 fResourceDict->unref(); // SkRefPtr and new both took a reference. 976 977 if (fGraphicStateResources.count()) { 978 SkRefPtr<SkPDFDict> extGState = new SkPDFDict(); 979 extGState->unref(); // SkRefPtr and new both took a reference. 980 for (int i = 0; i < fGraphicStateResources.count(); i++) { 981 SkString nameString("G"); 982 nameString.appendS32(i); 983 extGState->insert( 984 nameString.c_str(), 985 new SkPDFObjRef(fGraphicStateResources[i]))->unref(); 986 } 987 fResourceDict->insert("ExtGState", extGState.get()); 988 } 989 990 if (fXObjectResources.count()) { 991 SkRefPtr<SkPDFDict> xObjects = new SkPDFDict(); 992 xObjects->unref(); // SkRefPtr and new both took a reference. 993 for (int i = 0; i < fXObjectResources.count(); i++) { 994 SkString nameString("X"); 995 nameString.appendS32(i); 996 xObjects->insert( 997 nameString.c_str(), 998 new SkPDFObjRef(fXObjectResources[i]))->unref(); 999 } 1000 fResourceDict->insert("XObject", xObjects.get()); 1001 } 1002 1003 if (fFontResources.count()) { 1004 SkRefPtr<SkPDFDict> fonts = new SkPDFDict(); 1005 fonts->unref(); // SkRefPtr and new both took a reference. 1006 for (int i = 0; i < fFontResources.count(); i++) { 1007 SkString nameString("F"); 1008 nameString.appendS32(i); 1009 fonts->insert(nameString.c_str(), 1010 new SkPDFObjRef(fFontResources[i]))->unref(); 1011 } 1012 fResourceDict->insert("Font", fonts.get()); 1013 } 1014 1015 if (fShaderResources.count()) { 1016 SkRefPtr<SkPDFDict> patterns = new SkPDFDict(); 1017 patterns->unref(); // SkRefPtr and new both took a reference. 1018 for (int i = 0; i < fShaderResources.count(); i++) { 1019 SkString nameString("P"); 1020 nameString.appendS32(i); 1021 patterns->insert(nameString.c_str(), 1022 new SkPDFObjRef(fShaderResources[i]))->unref(); 1023 } 1024 fResourceDict->insert("Pattern", patterns.get()); 1025 } 1026 1027 // For compatibility, add all proc sets (only used for output to PS 1028 // devices). 1029 const char procs[][7] = {"PDF", "Text", "ImageB", "ImageC", "ImageI"}; 1030 SkRefPtr<SkPDFArray> procSets = new SkPDFArray(); 1031 procSets->unref(); // SkRefPtr and new both took a reference. 1032 procSets->reserve(SK_ARRAY_COUNT(procs)); 1033 for (size_t i = 0; i < SK_ARRAY_COUNT(procs); i++) 1034 procSets->appendName(procs[i]); 1035 fResourceDict->insert("ProcSet", procSets.get()); 1036 } 1037 return fResourceDict.get(); 1038 } 1039 1040 void SkPDFDevice::getResources(SkTDArray<SkPDFObject*>* resourceList) const { 1041 resourceList->setReserve(resourceList->count() + 1042 fGraphicStateResources.count() + 1043 fXObjectResources.count() + 1044 fFontResources.count() + 1045 fShaderResources.count()); 1046 for (int i = 0; i < fGraphicStateResources.count(); i++) { 1047 resourceList->push(fGraphicStateResources[i]); 1048 fGraphicStateResources[i]->ref(); 1049 fGraphicStateResources[i]->getResources(resourceList); 1050 } 1051 for (int i = 0; i < fXObjectResources.count(); i++) { 1052 resourceList->push(fXObjectResources[i]); 1053 fXObjectResources[i]->ref(); 1054 fXObjectResources[i]->getResources(resourceList); 1055 } 1056 for (int i = 0; i < fFontResources.count(); i++) { 1057 resourceList->push(fFontResources[i]); 1058 fFontResources[i]->ref(); 1059 fFontResources[i]->getResources(resourceList); 1060 } 1061 for (int i = 0; i < fShaderResources.count(); i++) { 1062 resourceList->push(fShaderResources[i]); 1063 fShaderResources[i]->ref(); 1064 fShaderResources[i]->getResources(resourceList); 1065 } 1066 } 1067 1068 const SkTDArray<SkPDFFont*>& SkPDFDevice::getFontResources() const { 1069 return fFontResources; 1070 } 1071 1072 SkRefPtr<SkPDFArray> SkPDFDevice::getMediaBox() const { 1073 SkRefPtr<SkPDFInt> zero = new SkPDFInt(0); 1074 zero->unref(); // SkRefPtr and new both took a reference. 1075 1076 SkRefPtr<SkPDFArray> mediaBox = new SkPDFArray(); 1077 mediaBox->unref(); // SkRefPtr and new both took a reference. 1078 mediaBox->reserve(4); 1079 mediaBox->append(zero.get()); 1080 mediaBox->append(zero.get()); 1081 mediaBox->appendInt(fPageSize.fWidth); 1082 mediaBox->appendInt(fPageSize.fHeight); 1083 return mediaBox; 1084 } 1085 1086 SkStream* SkPDFDevice::content() const { 1087 SkMemoryStream* result = new SkMemoryStream; 1088 result->setData(this->copyContentToData())->unref(); 1089 return result; 1090 } 1091 1092 void SkPDFDevice::copyContentEntriesToData(ContentEntry* entry, 1093 SkWStream* data) const { 1094 // TODO(ctguil): For margins, I'm not sure fExistingClipStack/Region is the 1095 // right thing to pass here. 1096 GraphicStackState gsState(fExistingClipStack, fExistingClipRegion, data); 1097 while (entry != NULL) { 1098 SkPoint translation; 1099 translation.iset(this->getOrigin()); 1100 translation.negate(); 1101 gsState.updateClip(entry->fState.fClipStack, entry->fState.fClipRegion, 1102 translation); 1103 gsState.updateMatrix(entry->fState.fMatrix); 1104 gsState.updateDrawingState(entry->fState); 1105 1106 SkAutoDataUnref copy(entry->fContent.copyToData()); 1107 data->write(copy.data(), copy.size()); 1108 entry = entry->fNext.get(); 1109 } 1110 gsState.drainStack(); 1111 } 1112 1113 SkData* SkPDFDevice::copyContentToData() const { 1114 SkDynamicMemoryWStream data; 1115 if (fInitialTransform.getType() != SkMatrix::kIdentity_Mask) { 1116 SkPDFUtils::AppendTransform(fInitialTransform, &data); 1117 } 1118 1119 // TODO(aayushkumar): Apply clip along the margins. Currently, webkit 1120 // colors the contentArea white before it starts drawing into it and 1121 // that currently acts as our clip. 1122 // Also, think about adding a transform here (or assume that the values 1123 // sent across account for that) 1124 SkPDFDevice::copyContentEntriesToData(fMarginContentEntries.get(), &data); 1125 1126 // If the content area is the entire page, then we don't need to clip 1127 // the content area (PDF area clips to the page size). Otherwise, 1128 // we have to clip to the content area; we've already applied the 1129 // initial transform, so just clip to the device size. 1130 if (fPageSize != fContentSize) { 1131 SkRect r = SkRect::MakeWH(this->width(), this->height()); 1132 emit_clip(NULL, &r, &data); 1133 } 1134 1135 SkPDFDevice::copyContentEntriesToData(fContentEntries.get(), &data); 1136 1137 // potentially we could cache this SkData, and only rebuild it if we 1138 // see that our state has changed. 1139 return data.copyToData(); 1140 } 1141 1142 void SkPDFDevice::createFormXObjectFromDevice( 1143 SkRefPtr<SkPDFFormXObject>* xobject) { 1144 *xobject = new SkPDFFormXObject(this); 1145 (*xobject)->unref(); // SkRefPtr and new both took a reference. 1146 // We always draw the form xobjects that we create back into the device, so 1147 // we simply preserve the font usage instead of pulling it out and merging 1148 // it back in later. 1149 cleanUp(false); // Reset this device to have no content. 1150 init(); 1151 } 1152 1153 void SkPDFDevice::clearClipFromContent(const SkClipStack* clipStack, 1154 const SkRegion& clipRegion) { 1155 if (clipRegion.isEmpty() || isContentEmpty()) { 1156 return; 1157 } 1158 SkRefPtr<SkPDFFormXObject> curContent; 1159 createFormXObjectFromDevice(&curContent); 1160 1161 // Redraw what we already had, but with the clip as a mask. 1162 drawFormXObjectWithClip(curContent.get(), clipStack, clipRegion, true); 1163 } 1164 1165 void SkPDFDevice::drawFormXObjectWithClip(SkPDFFormXObject* xobject, 1166 const SkClipStack* clipStack, 1167 const SkRegion& clipRegion, 1168 bool invertClip) { 1169 if (clipRegion.isEmpty() && !invertClip) { 1170 return; 1171 } 1172 1173 // Create the mask. 1174 SkMatrix identity; 1175 identity.reset(); 1176 SkDraw draw; 1177 draw.fMatrix = &identity; 1178 draw.fClip = &clipRegion; 1179 draw.fClipStack = clipStack; 1180 SkPaint stockPaint; 1181 this->drawPaint(draw, stockPaint); 1182 SkRefPtr<SkPDFFormXObject> maskFormXObject; 1183 createFormXObjectFromDevice(&maskFormXObject); 1184 SkRefPtr<SkPDFGraphicState> sMaskGS = 1185 SkPDFGraphicState::GetSMaskGraphicState(maskFormXObject.get(), 1186 invertClip); 1187 sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref. 1188 1189 // Draw the xobject with the clip as a mask. 1190 ScopedContentEntry content(this, &fExistingClipStack, fExistingClipRegion, 1191 identity, stockPaint); 1192 if (!content.entry()) { 1193 return; 1194 } 1195 SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()), 1196 &content.entry()->fContent); 1197 SkPDFUtils::DrawFormXObject(fXObjectResources.count(), 1198 &content.entry()->fContent); 1199 fXObjectResources.push(xobject); 1200 xobject->ref(); 1201 1202 sMaskGS = SkPDFGraphicState::GetNoSMaskGraphicState(); 1203 sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref. 1204 SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()), 1205 &content.entry()->fContent); 1206 } 1207 1208 ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack, 1209 const SkRegion& clipRegion, 1210 const SkMatrix& matrix, 1211 const SkPaint& paint, 1212 bool hasText, 1213 SkRefPtr<SkPDFFormXObject>* dst) { 1214 if (clipRegion.isEmpty()) { 1215 return NULL; 1216 } 1217 1218 // The clip stack can come from an SkDraw where it is technically optional. 1219 SkClipStack synthesizedClipStack; 1220 if (clipStack == NULL) { 1221 if (clipRegion == fExistingClipRegion) { 1222 clipStack = &fExistingClipStack; 1223 } else { 1224 // GraphicStackState::updateClip expects the clip stack to have 1225 // fExistingClip as a prefix, so start there, then set the clip 1226 // to the passed region. 1227 synthesizedClipStack = fExistingClipStack; 1228 SkPath clipPath; 1229 clipRegion.getBoundaryPath(&clipPath); 1230 synthesizedClipStack.clipDevPath(clipPath, SkRegion::kReplace_Op, 1231 false); 1232 clipStack = &synthesizedClipStack; 1233 } 1234 } 1235 1236 SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode; 1237 if (paint.getXfermode()) { 1238 paint.getXfermode()->asMode(&xfermode); 1239 } 1240 1241 if (xfermode == SkXfermode::kClear_Mode || 1242 xfermode == SkXfermode::kSrc_Mode) { 1243 this->clearClipFromContent(clipStack, clipRegion); 1244 } else if (xfermode == SkXfermode::kSrcIn_Mode || 1245 xfermode == SkXfermode::kDstIn_Mode || 1246 xfermode == SkXfermode::kSrcOut_Mode || 1247 xfermode == SkXfermode::kDstOut_Mode) { 1248 // For the following modes, we use both source and destination, but 1249 // we use one as a smask for the other, so we have to make form xobjects 1250 // out of both of them: SrcIn, DstIn, SrcOut, DstOut. 1251 if (isContentEmpty()) { 1252 return NULL; 1253 } else { 1254 createFormXObjectFromDevice(dst); 1255 } 1256 } 1257 // TODO(vandebo): Figure out how/if we can handle the following modes: 1258 // SrcAtop, DestAtop, Xor, Plus. 1259 1260 // These xfer modes don't draw source at all. 1261 if (xfermode == SkXfermode::kClear_Mode || 1262 xfermode == SkXfermode::kDst_Mode) { 1263 return NULL; 1264 } 1265 1266 ContentEntry* entry; 1267 SkTScopedPtr<ContentEntry> newEntry; 1268 1269 ContentEntry* lastContentEntry = getLastContentEntry(); 1270 if (lastContentEntry && lastContentEntry->fContent.getOffset() == 0) { 1271 entry = lastContentEntry; 1272 } else { 1273 newEntry.reset(new ContentEntry); 1274 entry = newEntry.get(); 1275 } 1276 1277 populateGraphicStateEntryFromPaint(matrix, *clipStack, clipRegion, paint, 1278 hasText, &entry->fState); 1279 if (lastContentEntry && xfermode != SkXfermode::kDstOver_Mode && 1280 entry->fState.compareInitialState(lastContentEntry->fState)) { 1281 return lastContentEntry; 1282 } 1283 1284 SkTScopedPtr<ContentEntry>* contentEntries = getContentEntries(); 1285 if (!lastContentEntry) { 1286 contentEntries->reset(entry); 1287 setLastContentEntry(entry); 1288 } else if (xfermode == SkXfermode::kDstOver_Mode) { 1289 entry->fNext.reset(contentEntries->release()); 1290 contentEntries->reset(entry); 1291 } else { 1292 lastContentEntry->fNext.reset(entry); 1293 setLastContentEntry(entry); 1294 } 1295 newEntry.release(); 1296 return entry; 1297 } 1298 1299 void SkPDFDevice::finishContentEntry(const SkXfermode::Mode xfermode, 1300 SkPDFFormXObject* dst) { 1301 if (xfermode != SkXfermode::kSrcIn_Mode && 1302 xfermode != SkXfermode::kDstIn_Mode && 1303 xfermode != SkXfermode::kSrcOut_Mode && 1304 xfermode != SkXfermode::kDstOut_Mode) { 1305 SkASSERT(!dst); 1306 return; 1307 } 1308 1309 ContentEntry* contentEntries = getContentEntries()->get(); 1310 SkASSERT(dst); 1311 SkASSERT(!contentEntries->fNext.get()); 1312 // We have to make a copy of these here because changing the current 1313 // content into a form xobject will destroy them. 1314 SkClipStack clipStack = contentEntries->fState.fClipStack; 1315 SkRegion clipRegion = contentEntries->fState.fClipRegion; 1316 1317 SkRefPtr<SkPDFFormXObject> srcFormXObject; 1318 if (!isContentEmpty()) { 1319 createFormXObjectFromDevice(&srcFormXObject); 1320 } 1321 1322 drawFormXObjectWithClip(dst, &clipStack, clipRegion, true); 1323 1324 // We've redrawn dst minus the clip area, if there's no src, we're done. 1325 if (!srcFormXObject.get()) { 1326 return; 1327 } 1328 1329 SkMatrix identity; 1330 identity.reset(); 1331 SkPaint stockPaint; 1332 ScopedContentEntry inClipContentEntry(this, &fExistingClipStack, 1333 fExistingClipRegion, identity, 1334 stockPaint); 1335 if (!inClipContentEntry.entry()) { 1336 return; 1337 } 1338 1339 SkRefPtr<SkPDFGraphicState> sMaskGS; 1340 if (xfermode == SkXfermode::kSrcIn_Mode || 1341 xfermode == SkXfermode::kSrcOut_Mode) { 1342 sMaskGS = SkPDFGraphicState::GetSMaskGraphicState( 1343 dst, xfermode == SkXfermode::kSrcOut_Mode); 1344 fXObjectResources.push(srcFormXObject.get()); 1345 srcFormXObject->ref(); 1346 } else { 1347 sMaskGS = SkPDFGraphicState::GetSMaskGraphicState( 1348 srcFormXObject.get(), xfermode == SkXfermode::kDstOut_Mode); 1349 // dst already added to fXObjectResources in drawFormXObjectWithClip. 1350 } 1351 sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref. 1352 SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()), 1353 &inClipContentEntry.entry()->fContent); 1354 1355 SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1, 1356 &inClipContentEntry.entry()->fContent); 1357 1358 sMaskGS = SkPDFGraphicState::GetNoSMaskGraphicState(); 1359 sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref. 1360 SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()), 1361 &inClipContentEntry.entry()->fContent); 1362 } 1363 1364 bool SkPDFDevice::isContentEmpty() { 1365 ContentEntry* contentEntries = getContentEntries()->get(); 1366 if (!contentEntries || contentEntries->fContent.getOffset() == 0) { 1367 SkASSERT(!contentEntries || !contentEntries->fNext.get()); 1368 return true; 1369 } 1370 return false; 1371 } 1372 1373 void SkPDFDevice::populateGraphicStateEntryFromPaint( 1374 const SkMatrix& matrix, 1375 const SkClipStack& clipStack, 1376 const SkRegion& clipRegion, 1377 const SkPaint& paint, 1378 bool hasText, 1379 GraphicStateEntry* entry) { 1380 SkASSERT(paint.getPathEffect() == NULL); 1381 1382 NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false); 1383 NOT_IMPLEMENTED(paint.getColorFilter() != NULL, false); 1384 1385 entry->fMatrix = matrix; 1386 entry->fClipStack = clipStack; 1387 entry->fClipRegion = clipRegion; 1388 1389 // PDF treats a shader as a color, so we only set one or the other. 1390 SkRefPtr<SkPDFObject> pdfShader; 1391 const SkShader* shader = paint.getShader(); 1392 SkColor color = paint.getColor(); 1393 if (shader) { 1394 // PDF positions patterns relative to the initial transform, so 1395 // we need to apply the current transform to the shader parameters. 1396 SkMatrix transform = matrix; 1397 transform.postConcat(fInitialTransform); 1398 1399 // PDF doesn't support kClamp_TileMode, so we simulate it by making 1400 // a pattern the size of the current clip. 1401 SkIRect bounds = clipRegion.getBounds(); 1402 pdfShader = SkPDFShader::GetPDFShader(*shader, transform, bounds); 1403 SkSafeUnref(pdfShader.get()); // getShader and SkRefPtr both took a ref 1404 1405 if (pdfShader.get()) { 1406 // pdfShader has been canonicalized so we can directly compare 1407 // pointers. 1408 int resourceIndex = fShaderResources.find(pdfShader.get()); 1409 if (resourceIndex < 0) { 1410 resourceIndex = fShaderResources.count(); 1411 fShaderResources.push(pdfShader.get()); 1412 pdfShader->ref(); 1413 } 1414 entry->fShaderIndex = resourceIndex; 1415 } else { 1416 // A color shader is treated as an invalid shader so we don't have 1417 // to set a shader just for a color. 1418 entry->fShaderIndex = -1; 1419 entry->fColor = 0; 1420 color = 0; 1421 1422 // Check for a color shader. 1423 SkShader::GradientInfo gradientInfo; 1424 SkColor gradientColor; 1425 gradientInfo.fColors = &gradientColor; 1426 gradientInfo.fColorOffsets = NULL; 1427 gradientInfo.fColorCount = 1; 1428 if (shader->asAGradient(&gradientInfo) == 1429 SkShader::kColor_GradientType) { 1430 entry->fColor = SkColorSetA(gradientColor, 0xFF); 1431 color = gradientColor; 1432 } 1433 } 1434 } else { 1435 entry->fShaderIndex = -1; 1436 entry->fColor = SkColorSetA(paint.getColor(), 0xFF); 1437 color = paint.getColor(); 1438 } 1439 1440 SkRefPtr<SkPDFGraphicState> newGraphicState; 1441 if (color == paint.getColor()) { 1442 newGraphicState = SkPDFGraphicState::GetGraphicStateForPaint(paint); 1443 } else { 1444 SkPaint newPaint = paint; 1445 newPaint.setColor(color); 1446 newGraphicState = SkPDFGraphicState::GetGraphicStateForPaint(newPaint); 1447 } 1448 newGraphicState->unref(); // getGraphicState and SkRefPtr both took a ref. 1449 int resourceIndex = addGraphicStateResource(newGraphicState.get()); 1450 entry->fGraphicStateIndex = resourceIndex; 1451 1452 if (hasText) { 1453 entry->fTextScaleX = paint.getTextScaleX(); 1454 entry->fTextFill = paint.getStyle(); 1455 } else { 1456 entry->fTextScaleX = 0; 1457 } 1458 } 1459 1460 int SkPDFDevice::addGraphicStateResource(SkPDFGraphicState* gs) { 1461 // Assumes that gs has been canonicalized (so we can directly compare 1462 // pointers). 1463 int result = fGraphicStateResources.find(gs); 1464 if (result < 0) { 1465 result = fGraphicStateResources.count(); 1466 fGraphicStateResources.push(gs); 1467 gs->ref(); 1468 } 1469 return result; 1470 } 1471 1472 void SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID, 1473 ContentEntry* contentEntry) { 1474 SkTypeface* typeface = paint.getTypeface(); 1475 if (contentEntry->fState.fFont == NULL || 1476 contentEntry->fState.fTextSize != paint.getTextSize() || 1477 !contentEntry->fState.fFont->hasGlyph(glyphID)) { 1478 int fontIndex = getFontResourceIndex(typeface, glyphID); 1479 contentEntry->fContent.writeText("/F"); 1480 contentEntry->fContent.writeDecAsText(fontIndex); 1481 contentEntry->fContent.writeText(" "); 1482 SkPDFScalar::Append(paint.getTextSize(), &contentEntry->fContent); 1483 contentEntry->fContent.writeText(" Tf\n"); 1484 contentEntry->fState.fFont = fFontResources[fontIndex]; 1485 } 1486 } 1487 1488 int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) { 1489 SkRefPtr<SkPDFFont> newFont = SkPDFFont::GetFontResource(typeface, glyphID); 1490 newFont->unref(); // getFontResource and SkRefPtr both took a ref. 1491 int resourceIndex = fFontResources.find(newFont.get()); 1492 if (resourceIndex < 0) { 1493 resourceIndex = fFontResources.count(); 1494 fFontResources.push(newFont.get()); 1495 newFont->ref(); 1496 } 1497 return resourceIndex; 1498 } 1499 1500 void SkPDFDevice::internalDrawBitmap(const SkMatrix& matrix, 1501 const SkClipStack* clipStack, 1502 const SkRegion& clipRegion, 1503 const SkBitmap& bitmap, 1504 const SkIRect* srcRect, 1505 const SkPaint& paint) { 1506 SkMatrix scaled; 1507 // Adjust for origin flip. 1508 scaled.setScale(SK_Scalar1, -SK_Scalar1); 1509 scaled.postTranslate(0, SK_Scalar1); 1510 // Scale the image up from 1x1 to WxH. 1511 SkIRect subset = SkIRect::MakeWH(bitmap.width(), bitmap.height()); 1512 scaled.postScale(SkIntToScalar(subset.width()), 1513 SkIntToScalar(subset.height())); 1514 scaled.postConcat(matrix); 1515 ScopedContentEntry content(this, clipStack, clipRegion, scaled, paint); 1516 if (!content.entry()) { 1517 return; 1518 } 1519 1520 if (srcRect && !subset.intersect(*srcRect)) { 1521 return; 1522 } 1523 1524 SkPDFImage* image = SkPDFImage::CreateImage(bitmap, subset, paint); 1525 if (!image) { 1526 return; 1527 } 1528 1529 fXObjectResources.push(image); // Transfer reference. 1530 SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1, 1531 &content.entry()->fContent); 1532 } 1533 1534 bool SkPDFDevice::onReadPixels(const SkBitmap& bitmap, int x, int y, 1535 SkCanvas::Config8888) { 1536 return false; 1537 } 1538 1539 bool SkPDFDevice::allowImageFilter(SkImageFilter*) { 1540 return false; 1541 } 1542 1543