1 /* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkPDFDevice.h" 9 10 #include "SkAnnotation.h" 11 #include "SkBitmapDevice.h" 12 #include "SkColor.h" 13 #include "SkClipStack.h" 14 #include "SkData.h" 15 #include "SkDraw.h" 16 #include "SkFontHost.h" 17 #include "SkGlyphCache.h" 18 #include "SkPaint.h" 19 #include "SkPath.h" 20 #include "SkPathOps.h" 21 #include "SkPDFFont.h" 22 #include "SkPDFFormXObject.h" 23 #include "SkPDFGraphicState.h" 24 #include "SkPDFImage.h" 25 #include "SkPDFResourceDict.h" 26 #include "SkPDFShader.h" 27 #include "SkPDFStream.h" 28 #include "SkPDFTypes.h" 29 #include "SkPDFUtils.h" 30 #include "SkRect.h" 31 #include "SkRRect.h" 32 #include "SkString.h" 33 #include "SkSurface.h" 34 #include "SkTextFormatParams.h" 35 #include "SkTemplates.h" 36 #include "SkTypefacePriv.h" 37 #include "SkTSet.h" 38 39 #define DPI_FOR_RASTER_SCALE_ONE 72 40 41 // Utility functions 42 43 static void emit_pdf_color(SkColor color, SkWStream* result) { 44 SkASSERT(SkColorGetA(color) == 0xFF); // We handle alpha elsewhere. 45 SkScalar colorMax = SkIntToScalar(0xFF); 46 SkPDFScalar::Append( 47 SkScalarDiv(SkIntToScalar(SkColorGetR(color)), colorMax), result); 48 result->writeText(" "); 49 SkPDFScalar::Append( 50 SkScalarDiv(SkIntToScalar(SkColorGetG(color)), colorMax), result); 51 result->writeText(" "); 52 SkPDFScalar::Append( 53 SkScalarDiv(SkIntToScalar(SkColorGetB(color)), colorMax), result); 54 result->writeText(" "); 55 } 56 57 static SkPaint calculate_text_paint(const SkPaint& paint) { 58 SkPaint result = paint; 59 if (result.isFakeBoldText()) { 60 SkScalar fakeBoldScale = SkScalarInterpFunc(result.getTextSize(), 61 kStdFakeBoldInterpKeys, 62 kStdFakeBoldInterpValues, 63 kStdFakeBoldInterpLength); 64 SkScalar width = SkScalarMul(result.getTextSize(), fakeBoldScale); 65 if (result.getStyle() == SkPaint::kFill_Style) { 66 result.setStyle(SkPaint::kStrokeAndFill_Style); 67 } else { 68 width += result.getStrokeWidth(); 69 } 70 result.setStrokeWidth(width); 71 } 72 return result; 73 } 74 75 // Stolen from measure_text in SkDraw.cpp and then tweaked. 76 static void align_text(SkDrawCacheProc glyphCacheProc, const SkPaint& paint, 77 const uint16_t* glyphs, size_t len, 78 SkScalar* x, SkScalar* y) { 79 if (paint.getTextAlign() == SkPaint::kLeft_Align) { 80 return; 81 } 82 83 SkMatrix ident; 84 ident.reset(); 85 SkAutoGlyphCache autoCache(paint, NULL, &ident); 86 SkGlyphCache* cache = autoCache.getCache(); 87 88 const char* start = reinterpret_cast<const char*>(glyphs); 89 const char* stop = reinterpret_cast<const char*>(glyphs + len); 90 SkFixed xAdv = 0, yAdv = 0; 91 92 // TODO(vandebo): This probably needs to take kerning into account. 93 while (start < stop) { 94 const SkGlyph& glyph = glyphCacheProc(cache, &start, 0, 0); 95 xAdv += glyph.fAdvanceX; 96 yAdv += glyph.fAdvanceY; 97 }; 98 if (paint.getTextAlign() == SkPaint::kLeft_Align) { 99 return; 100 } 101 102 SkScalar xAdj = SkFixedToScalar(xAdv); 103 SkScalar yAdj = SkFixedToScalar(yAdv); 104 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 105 xAdj = SkScalarHalf(xAdj); 106 yAdj = SkScalarHalf(yAdj); 107 } 108 *x = *x - xAdj; 109 *y = *y - yAdj; 110 } 111 112 static int max_glyphid_for_typeface(SkTypeface* typeface) { 113 SkAutoResolveDefaultTypeface autoResolve(typeface); 114 typeface = autoResolve.get(); 115 return typeface->countGlyphs() - 1; 116 } 117 118 typedef SkAutoSTMalloc<128, uint16_t> SkGlyphStorage; 119 120 static int force_glyph_encoding(const SkPaint& paint, const void* text, 121 size_t len, SkGlyphStorage* storage, 122 const uint16_t** glyphIDs) { 123 // Make sure we have a glyph id encoding. 124 if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) { 125 int numGlyphs = paint.textToGlyphs(text, len, NULL); 126 storage->reset(numGlyphs); 127 paint.textToGlyphs(text, len, storage->get()); 128 *glyphIDs = storage->get(); 129 return numGlyphs; 130 } 131 132 // For user supplied glyph ids we need to validate them. 133 SkASSERT((len & 1) == 0); 134 int numGlyphs = SkToInt(len / 2); 135 const uint16_t* input = static_cast<const uint16_t*>(text); 136 137 int maxGlyphID = max_glyphid_for_typeface(paint.getTypeface()); 138 int validated; 139 for (validated = 0; validated < numGlyphs; ++validated) { 140 if (input[validated] > maxGlyphID) { 141 break; 142 } 143 } 144 if (validated >= numGlyphs) { 145 *glyphIDs = static_cast<const uint16_t*>(text); 146 return numGlyphs; 147 } 148 149 // Silently drop anything out of range. 150 storage->reset(numGlyphs); 151 if (validated > 0) { 152 memcpy(storage->get(), input, validated * sizeof(uint16_t)); 153 } 154 155 for (int i = validated; i < numGlyphs; ++i) { 156 storage->get()[i] = input[i]; 157 if (input[i] > maxGlyphID) { 158 storage->get()[i] = 0; 159 } 160 } 161 *glyphIDs = storage->get(); 162 return numGlyphs; 163 } 164 165 static void set_text_transform(SkScalar x, SkScalar y, SkScalar textSkewX, 166 SkWStream* content) { 167 // Flip the text about the x-axis to account for origin swap and include 168 // the passed parameters. 169 content->writeText("1 0 "); 170 SkPDFScalar::Append(0 - textSkewX, content); 171 content->writeText(" -1 "); 172 SkPDFScalar::Append(x, content); 173 content->writeText(" "); 174 SkPDFScalar::Append(y, content); 175 content->writeText(" Tm\n"); 176 } 177 178 // It is important to not confuse GraphicStateEntry with SkPDFGraphicState, the 179 // later being our representation of an object in the PDF file. 180 struct GraphicStateEntry { 181 GraphicStateEntry(); 182 183 // Compare the fields we care about when setting up a new content entry. 184 bool compareInitialState(const GraphicStateEntry& b); 185 186 SkMatrix fMatrix; 187 // We can't do set operations on Paths, though PDF natively supports 188 // intersect. If the clip stack does anything other than intersect, 189 // we have to fall back to the region. Treat fClipStack as authoritative. 190 // See http://code.google.com/p/skia/issues/detail?id=221 191 SkClipStack fClipStack; 192 SkRegion fClipRegion; 193 194 // When emitting the content entry, we will ensure the graphic state 195 // is set to these values first. 196 SkColor fColor; 197 SkScalar fTextScaleX; // Zero means we don't care what the value is. 198 SkPaint::Style fTextFill; // Only if TextScaleX is non-zero. 199 int fShaderIndex; 200 int fGraphicStateIndex; 201 202 // We may change the font (i.e. for Type1 support) within a 203 // ContentEntry. This is the one currently in effect, or NULL if none. 204 SkPDFFont* fFont; 205 // In PDF, text size has no default value. It is only valid if fFont is 206 // not NULL. 207 SkScalar fTextSize; 208 }; 209 210 GraphicStateEntry::GraphicStateEntry() : fColor(SK_ColorBLACK), 211 fTextScaleX(SK_Scalar1), 212 fTextFill(SkPaint::kFill_Style), 213 fShaderIndex(-1), 214 fGraphicStateIndex(-1), 215 fFont(NULL), 216 fTextSize(SK_ScalarNaN) { 217 fMatrix.reset(); 218 } 219 220 bool GraphicStateEntry::compareInitialState(const GraphicStateEntry& cur) { 221 return fColor == cur.fColor && 222 fShaderIndex == cur.fShaderIndex && 223 fGraphicStateIndex == cur.fGraphicStateIndex && 224 fMatrix == cur.fMatrix && 225 fClipStack == cur.fClipStack && 226 (fTextScaleX == 0 || 227 (fTextScaleX == cur.fTextScaleX && fTextFill == cur.fTextFill)); 228 } 229 230 class GraphicStackState { 231 public: 232 GraphicStackState(const SkClipStack& existingClipStack, 233 const SkRegion& existingClipRegion, 234 SkWStream* contentStream) 235 : fStackDepth(0), 236 fContentStream(contentStream) { 237 fEntries[0].fClipStack = existingClipStack; 238 fEntries[0].fClipRegion = existingClipRegion; 239 } 240 241 void updateClip(const SkClipStack& clipStack, const SkRegion& clipRegion, 242 const SkPoint& translation); 243 void updateMatrix(const SkMatrix& matrix); 244 void updateDrawingState(const GraphicStateEntry& state); 245 246 void drainStack(); 247 248 private: 249 void push(); 250 void pop(); 251 GraphicStateEntry* currentEntry() { return &fEntries[fStackDepth]; } 252 253 // Conservative limit on save depth, see impl. notes in PDF 1.4 spec. 254 static const int kMaxStackDepth = 12; 255 GraphicStateEntry fEntries[kMaxStackDepth + 1]; 256 int fStackDepth; 257 SkWStream* fContentStream; 258 }; 259 260 void GraphicStackState::drainStack() { 261 while (fStackDepth) { 262 pop(); 263 } 264 } 265 266 void GraphicStackState::push() { 267 SkASSERT(fStackDepth < kMaxStackDepth); 268 fContentStream->writeText("q\n"); 269 fStackDepth++; 270 fEntries[fStackDepth] = fEntries[fStackDepth - 1]; 271 } 272 273 void GraphicStackState::pop() { 274 SkASSERT(fStackDepth > 0); 275 fContentStream->writeText("Q\n"); 276 fStackDepth--; 277 } 278 279 // This function initializes iter to be an iterator on the "stack" argument 280 // and then skips over the leading entries as specified in prefix. It requires 281 // and asserts that "prefix" will be a prefix to "stack." 282 static void skip_clip_stack_prefix(const SkClipStack& prefix, 283 const SkClipStack& stack, 284 SkClipStack::Iter* iter) { 285 SkClipStack::B2TIter prefixIter(prefix); 286 iter->reset(stack, SkClipStack::Iter::kBottom_IterStart); 287 288 const SkClipStack::Element* prefixEntry; 289 const SkClipStack::Element* iterEntry; 290 291 for (prefixEntry = prefixIter.next(); prefixEntry; 292 prefixEntry = prefixIter.next()) { 293 iterEntry = iter->next(); 294 SkASSERT(iterEntry); 295 // Because of SkClipStack does internal intersection, the last clip 296 // entry may differ. 297 if (*prefixEntry != *iterEntry) { 298 SkASSERT(prefixEntry->getOp() == SkRegion::kIntersect_Op); 299 SkASSERT(iterEntry->getOp() == SkRegion::kIntersect_Op); 300 SkASSERT(iterEntry->getType() == prefixEntry->getType()); 301 // back up the iterator by one 302 iter->prev(); 303 prefixEntry = prefixIter.next(); 304 break; 305 } 306 } 307 308 SkASSERT(prefixEntry == NULL); 309 } 310 311 static void emit_clip(SkPath* clipPath, SkRect* clipRect, 312 SkWStream* contentStream) { 313 SkASSERT(clipPath || clipRect); 314 315 SkPath::FillType clipFill; 316 if (clipPath) { 317 SkPDFUtils::EmitPath(*clipPath, SkPaint::kFill_Style, contentStream); 318 clipFill = clipPath->getFillType(); 319 } else { 320 SkPDFUtils::AppendRectangle(*clipRect, contentStream); 321 clipFill = SkPath::kWinding_FillType; 322 } 323 324 NOT_IMPLEMENTED(clipFill == SkPath::kInverseEvenOdd_FillType, false); 325 NOT_IMPLEMENTED(clipFill == SkPath::kInverseWinding_FillType, false); 326 if (clipFill == SkPath::kEvenOdd_FillType) { 327 contentStream->writeText("W* n\n"); 328 } else { 329 contentStream->writeText("W n\n"); 330 } 331 } 332 333 #ifdef SK_PDF_USE_PATHOPS 334 /* Calculate an inverted path's equivalent non-inverted path, given the 335 * canvas bounds. 336 * outPath may alias with invPath (since this is supported by PathOps). 337 */ 338 static bool calculate_inverse_path(const SkRect& bounds, const SkPath& invPath, 339 SkPath* outPath) { 340 SkASSERT(invPath.isInverseFillType()); 341 342 SkPath clipPath; 343 clipPath.addRect(bounds); 344 345 return Op(clipPath, invPath, kIntersect_PathOp, outPath); 346 } 347 348 // Sanity check the numerical values of the SkRegion ops and PathOps ops 349 // enums so region_op_to_pathops_op can do a straight passthrough cast. 350 // If these are failing, it may be necessary to make region_op_to_pathops_op 351 // do more. 352 SK_COMPILE_ASSERT(SkRegion::kDifference_Op == (int)kDifference_PathOp, 353 region_pathop_mismatch); 354 SK_COMPILE_ASSERT(SkRegion::kIntersect_Op == (int)kIntersect_PathOp, 355 region_pathop_mismatch); 356 SK_COMPILE_ASSERT(SkRegion::kUnion_Op == (int)kUnion_PathOp, 357 region_pathop_mismatch); 358 SK_COMPILE_ASSERT(SkRegion::kXOR_Op == (int)kXOR_PathOp, 359 region_pathop_mismatch); 360 SK_COMPILE_ASSERT(SkRegion::kReverseDifference_Op == 361 (int)kReverseDifference_PathOp, 362 region_pathop_mismatch); 363 364 static SkPathOp region_op_to_pathops_op(SkRegion::Op op) { 365 SkASSERT(op >= 0); 366 SkASSERT(op <= SkRegion::kReverseDifference_Op); 367 return (SkPathOp)op; 368 } 369 370 /* Uses Path Ops to calculate a vector SkPath clip from a clip stack. 371 * Returns true if successful, or false if not successful. 372 * If successful, the resulting clip is stored in outClipPath. 373 * If not successful, outClipPath is undefined, and a fallback method 374 * should be used. 375 */ 376 static bool get_clip_stack_path(const SkMatrix& transform, 377 const SkClipStack& clipStack, 378 const SkRegion& clipRegion, 379 SkPath* outClipPath) { 380 outClipPath->reset(); 381 outClipPath->setFillType(SkPath::kInverseWinding_FillType); 382 383 const SkClipStack::Element* clipEntry; 384 SkClipStack::Iter iter; 385 iter.reset(clipStack, SkClipStack::Iter::kBottom_IterStart); 386 for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) { 387 SkPath entryPath; 388 if (SkClipStack::Element::kEmpty_Type == clipEntry->getType()) { 389 outClipPath->reset(); 390 outClipPath->setFillType(SkPath::kInverseWinding_FillType); 391 continue; 392 } else { 393 clipEntry->asPath(&entryPath); 394 } 395 entryPath.transform(transform); 396 397 if (SkRegion::kReplace_Op == clipEntry->getOp()) { 398 *outClipPath = entryPath; 399 } else { 400 SkPathOp op = region_op_to_pathops_op(clipEntry->getOp()); 401 if (!Op(*outClipPath, entryPath, op, outClipPath)) { 402 return false; 403 } 404 } 405 } 406 407 if (outClipPath->isInverseFillType()) { 408 // The bounds are slightly outset to ensure this is correct in the 409 // face of floating-point accuracy and possible SkRegion bitmap 410 // approximations. 411 SkRect clipBounds = SkRect::Make(clipRegion.getBounds()); 412 clipBounds.outset(SK_Scalar1, SK_Scalar1); 413 if (!calculate_inverse_path(clipBounds, *outClipPath, outClipPath)) { 414 return false; 415 } 416 } 417 return true; 418 } 419 #endif 420 421 // TODO(vandebo): Take advantage of SkClipStack::getSaveCount(), the PDF 422 // graphic state stack, and the fact that we can know all the clips used 423 // on the page to optimize this. 424 void GraphicStackState::updateClip(const SkClipStack& clipStack, 425 const SkRegion& clipRegion, 426 const SkPoint& translation) { 427 if (clipStack == currentEntry()->fClipStack) { 428 return; 429 } 430 431 while (fStackDepth > 0) { 432 pop(); 433 if (clipStack == currentEntry()->fClipStack) { 434 return; 435 } 436 } 437 push(); 438 439 currentEntry()->fClipStack = clipStack; 440 currentEntry()->fClipRegion = clipRegion; 441 442 SkMatrix transform; 443 transform.setTranslate(translation.fX, translation.fY); 444 445 #ifdef SK_PDF_USE_PATHOPS 446 SkPath clipPath; 447 if (get_clip_stack_path(transform, clipStack, clipRegion, &clipPath)) { 448 emit_clip(&clipPath, NULL, fContentStream); 449 return; 450 } 451 #endif 452 // gsState->initialEntry()->fClipStack/Region specifies the clip that has 453 // already been applied. (If this is a top level device, then it specifies 454 // a clip to the content area. If this is a layer, then it specifies 455 // the clip in effect when the layer was created.) There's no need to 456 // reapply that clip; SKCanvas's SkDrawIter will draw anything outside the 457 // initial clip on the parent layer. (This means there's a bug if the user 458 // expands the clip and then uses any xfer mode that uses dst: 459 // http://code.google.com/p/skia/issues/detail?id=228 ) 460 SkClipStack::Iter iter; 461 skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter); 462 463 // If the clip stack does anything other than intersect or if it uses 464 // an inverse fill type, we have to fall back to the clip region. 465 bool needRegion = false; 466 const SkClipStack::Element* clipEntry; 467 for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) { 468 if (clipEntry->getOp() != SkRegion::kIntersect_Op || 469 clipEntry->isInverseFilled()) { 470 needRegion = true; 471 break; 472 } 473 } 474 475 if (needRegion) { 476 SkPath clipPath; 477 SkAssertResult(clipRegion.getBoundaryPath(&clipPath)); 478 emit_clip(&clipPath, NULL, fContentStream); 479 } else { 480 skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter); 481 const SkClipStack::Element* clipEntry; 482 for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) { 483 SkASSERT(clipEntry->getOp() == SkRegion::kIntersect_Op); 484 switch (clipEntry->getType()) { 485 case SkClipStack::Element::kRect_Type: { 486 SkRect translatedClip; 487 transform.mapRect(&translatedClip, clipEntry->getRect()); 488 emit_clip(NULL, &translatedClip, fContentStream); 489 break; 490 } 491 default: { 492 SkPath translatedPath; 493 clipEntry->asPath(&translatedPath); 494 translatedPath.transform(transform, &translatedPath); 495 emit_clip(&translatedPath, NULL, fContentStream); 496 break; 497 } 498 } 499 } 500 } 501 } 502 503 void GraphicStackState::updateMatrix(const SkMatrix& matrix) { 504 if (matrix == currentEntry()->fMatrix) { 505 return; 506 } 507 508 if (currentEntry()->fMatrix.getType() != SkMatrix::kIdentity_Mask) { 509 SkASSERT(fStackDepth > 0); 510 SkASSERT(fEntries[fStackDepth].fClipStack == 511 fEntries[fStackDepth -1].fClipStack); 512 pop(); 513 514 SkASSERT(currentEntry()->fMatrix.getType() == SkMatrix::kIdentity_Mask); 515 } 516 if (matrix.getType() == SkMatrix::kIdentity_Mask) { 517 return; 518 } 519 520 push(); 521 SkPDFUtils::AppendTransform(matrix, fContentStream); 522 currentEntry()->fMatrix = matrix; 523 } 524 525 void GraphicStackState::updateDrawingState(const GraphicStateEntry& state) { 526 // PDF treats a shader as a color, so we only set one or the other. 527 if (state.fShaderIndex >= 0) { 528 if (state.fShaderIndex != currentEntry()->fShaderIndex) { 529 SkPDFUtils::ApplyPattern(state.fShaderIndex, fContentStream); 530 currentEntry()->fShaderIndex = state.fShaderIndex; 531 } 532 } else { 533 if (state.fColor != currentEntry()->fColor || 534 currentEntry()->fShaderIndex >= 0) { 535 emit_pdf_color(state.fColor, fContentStream); 536 fContentStream->writeText("RG "); 537 emit_pdf_color(state.fColor, fContentStream); 538 fContentStream->writeText("rg\n"); 539 currentEntry()->fColor = state.fColor; 540 currentEntry()->fShaderIndex = -1; 541 } 542 } 543 544 if (state.fGraphicStateIndex != currentEntry()->fGraphicStateIndex) { 545 SkPDFUtils::ApplyGraphicState(state.fGraphicStateIndex, fContentStream); 546 currentEntry()->fGraphicStateIndex = state.fGraphicStateIndex; 547 } 548 549 if (state.fTextScaleX) { 550 if (state.fTextScaleX != currentEntry()->fTextScaleX) { 551 SkScalar pdfScale = SkScalarMul(state.fTextScaleX, 552 SkIntToScalar(100)); 553 SkPDFScalar::Append(pdfScale, fContentStream); 554 fContentStream->writeText(" Tz\n"); 555 currentEntry()->fTextScaleX = state.fTextScaleX; 556 } 557 if (state.fTextFill != currentEntry()->fTextFill) { 558 SK_COMPILE_ASSERT(SkPaint::kFill_Style == 0, enum_must_match_value); 559 SK_COMPILE_ASSERT(SkPaint::kStroke_Style == 1, 560 enum_must_match_value); 561 SK_COMPILE_ASSERT(SkPaint::kStrokeAndFill_Style == 2, 562 enum_must_match_value); 563 fContentStream->writeDecAsText(state.fTextFill); 564 fContentStream->writeText(" Tr\n"); 565 currentEntry()->fTextFill = state.fTextFill; 566 } 567 } 568 } 569 570 SkBaseDevice* SkPDFDevice::onCreateDevice(const SkImageInfo& info, Usage usage) { 571 // PDF does not support image filters, so render them on CPU. 572 // Note that this rendering is done at "screen" resolution (100dpi), not 573 // printer resolution. 574 // FIXME: It may be possible to express some filters natively using PDF 575 // to improve quality and file size (http://skbug.com/3043) 576 if (kImageFilter_Usage == usage) { 577 return SkBitmapDevice::Create(info); 578 } 579 580 SkMatrix initialTransform; 581 initialTransform.reset(); 582 SkISize size = SkISize::Make(info.width(), info.height()); 583 return SkNEW_ARGS(SkPDFDevice, (size, size, initialTransform)); 584 } 585 586 587 struct ContentEntry { 588 GraphicStateEntry fState; 589 SkDynamicMemoryWStream fContent; 590 SkAutoTDelete<ContentEntry> fNext; 591 592 // If the stack is too deep we could get Stack Overflow. 593 // So we manually destruct the object. 594 ~ContentEntry() { 595 ContentEntry* val = fNext.detach(); 596 while (val != NULL) { 597 ContentEntry* valNext = val->fNext.detach(); 598 // When the destructor is called, fNext is NULL and exits. 599 delete val; 600 val = valNext; 601 } 602 } 603 }; 604 605 // A helper class to automatically finish a ContentEntry at the end of a 606 // drawing method and maintain the state needed between set up and finish. 607 class ScopedContentEntry { 608 public: 609 ScopedContentEntry(SkPDFDevice* device, const SkDraw& draw, 610 const SkPaint& paint, bool hasText = false) 611 : fDevice(device), 612 fContentEntry(NULL), 613 fXfermode(SkXfermode::kSrcOver_Mode), 614 fDstFormXObject(NULL) { 615 init(draw.fClipStack, *draw.fClip, *draw.fMatrix, paint, hasText); 616 } 617 ScopedContentEntry(SkPDFDevice* device, const SkClipStack* clipStack, 618 const SkRegion& clipRegion, const SkMatrix& matrix, 619 const SkPaint& paint, bool hasText = false) 620 : fDevice(device), 621 fContentEntry(NULL), 622 fXfermode(SkXfermode::kSrcOver_Mode), 623 fDstFormXObject(NULL) { 624 init(clipStack, clipRegion, matrix, paint, hasText); 625 } 626 627 ~ScopedContentEntry() { 628 if (fContentEntry) { 629 SkPath* shape = &fShape; 630 if (shape->isEmpty()) { 631 shape = NULL; 632 } 633 fDevice->finishContentEntry(fXfermode, fDstFormXObject, shape); 634 } 635 SkSafeUnref(fDstFormXObject); 636 } 637 638 ContentEntry* entry() { return fContentEntry; } 639 640 /* Returns true when we explicitly need the shape of the drawing. */ 641 bool needShape() { 642 switch (fXfermode) { 643 case SkXfermode::kClear_Mode: 644 case SkXfermode::kSrc_Mode: 645 case SkXfermode::kSrcIn_Mode: 646 case SkXfermode::kSrcOut_Mode: 647 case SkXfermode::kDstIn_Mode: 648 case SkXfermode::kDstOut_Mode: 649 case SkXfermode::kSrcATop_Mode: 650 case SkXfermode::kDstATop_Mode: 651 case SkXfermode::kModulate_Mode: 652 return true; 653 default: 654 return false; 655 } 656 } 657 658 /* Returns true unless we only need the shape of the drawing. */ 659 bool needSource() { 660 if (fXfermode == SkXfermode::kClear_Mode) { 661 return false; 662 } 663 return true; 664 } 665 666 /* If the shape is different than the alpha component of the content, then 667 * setShape should be called with the shape. In particular, images and 668 * devices have rectangular shape. 669 */ 670 void setShape(const SkPath& shape) { 671 fShape = shape; 672 } 673 674 private: 675 SkPDFDevice* fDevice; 676 ContentEntry* fContentEntry; 677 SkXfermode::Mode fXfermode; 678 SkPDFFormXObject* fDstFormXObject; 679 SkPath fShape; 680 681 void init(const SkClipStack* clipStack, const SkRegion& clipRegion, 682 const SkMatrix& matrix, const SkPaint& paint, bool hasText) { 683 // Shape has to be flatten before we get here. 684 if (matrix.hasPerspective()) { 685 NOT_IMPLEMENTED(!matrix.hasPerspective(), false); 686 return; 687 } 688 if (paint.getXfermode()) { 689 paint.getXfermode()->asMode(&fXfermode); 690 } 691 fContentEntry = fDevice->setUpContentEntry(clipStack, clipRegion, 692 matrix, paint, hasText, 693 &fDstFormXObject); 694 } 695 }; 696 697 //////////////////////////////////////////////////////////////////////////////// 698 699 static inline SkImageInfo make_content_info(const SkISize& contentSize, 700 const SkMatrix* initialTransform) { 701 SkImageInfo info; 702 if (initialTransform) { 703 // Compute the size of the drawing area. 704 SkVector drawingSize; 705 SkMatrix inverse; 706 drawingSize.set(SkIntToScalar(contentSize.fWidth), 707 SkIntToScalar(contentSize.fHeight)); 708 if (!initialTransform->invert(&inverse)) { 709 // This shouldn't happen, initial transform should be invertible. 710 SkASSERT(false); 711 inverse.reset(); 712 } 713 inverse.mapVectors(&drawingSize, 1); 714 SkISize size = SkSize::Make(drawingSize.fX, drawingSize.fY).toRound(); 715 info = SkImageInfo::MakeUnknown(abs(size.fWidth), abs(size.fHeight)); 716 } else { 717 info = SkImageInfo::MakeUnknown(abs(contentSize.fWidth), 718 abs(contentSize.fHeight)); 719 } 720 return info; 721 } 722 723 // TODO(vandebo) change pageSize to SkSize. 724 SkPDFDevice::SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize, 725 const SkMatrix& initialTransform) 726 : fPageSize(pageSize) 727 , fContentSize(contentSize) 728 , fLastContentEntry(NULL) 729 , fLastMarginContentEntry(NULL) 730 , fClipStack(NULL) 731 , fEncoder(NULL) 732 , fRasterDpi(72.0f) 733 { 734 const SkImageInfo info = make_content_info(contentSize, &initialTransform); 735 736 // Just report that PDF does not supports perspective in the 737 // initial transform. 738 NOT_IMPLEMENTED(initialTransform.hasPerspective(), true); 739 740 // Skia generally uses the top left as the origin but PDF natively has the 741 // origin at the bottom left. This matrix corrects for that. But that only 742 // needs to be done once, we don't do it when layering. 743 fInitialTransform.setTranslate(0, SkIntToScalar(pageSize.fHeight)); 744 fInitialTransform.preScale(SK_Scalar1, -SK_Scalar1); 745 fInitialTransform.preConcat(initialTransform); 746 fLegacyBitmap.setInfo(info); 747 748 SkIRect existingClip = SkIRect::MakeWH(info.width(), info.height()); 749 fExistingClipRegion.setRect(existingClip); 750 this->init(); 751 } 752 753 // TODO(vandebo) change layerSize to SkSize. 754 SkPDFDevice::SkPDFDevice(const SkISize& layerSize, 755 const SkClipStack& existingClipStack, 756 const SkRegion& existingClipRegion) 757 : fPageSize(layerSize) 758 , fContentSize(layerSize) 759 , fExistingClipStack(existingClipStack) 760 , fExistingClipRegion(existingClipRegion) 761 , fLastContentEntry(NULL) 762 , fLastMarginContentEntry(NULL) 763 , fClipStack(NULL) 764 , fEncoder(NULL) 765 , fRasterDpi(72.0f) 766 { 767 fInitialTransform.reset(); 768 fLegacyBitmap.setInfo(make_content_info(layerSize, NULL)); 769 770 this->init(); 771 } 772 773 SkPDFDevice::~SkPDFDevice() { 774 this->cleanUp(true); 775 } 776 777 void SkPDFDevice::init() { 778 fAnnotations = NULL; 779 fResourceDict = NULL; 780 fContentEntries.free(); 781 fLastContentEntry = NULL; 782 fMarginContentEntries.free(); 783 fLastMarginContentEntry = NULL; 784 fDrawingArea = kContent_DrawingArea; 785 if (fFontGlyphUsage.get() == NULL) { 786 fFontGlyphUsage.reset(new SkPDFGlyphSetMap()); 787 } 788 } 789 790 void SkPDFDevice::cleanUp(bool clearFontUsage) { 791 fGraphicStateResources.unrefAll(); 792 fXObjectResources.unrefAll(); 793 fFontResources.unrefAll(); 794 fShaderResources.unrefAll(); 795 SkSafeUnref(fAnnotations); 796 SkSafeUnref(fResourceDict); 797 fNamedDestinations.deleteAll(); 798 799 if (clearFontUsage) { 800 fFontGlyphUsage->reset(); 801 } 802 } 803 804 void SkPDFDevice::clear(SkColor color) { 805 this->cleanUp(true); 806 this->init(); 807 808 SkPaint paint; 809 paint.setColor(color); 810 paint.setStyle(SkPaint::kFill_Style); 811 SkMatrix identity; 812 identity.reset(); 813 ScopedContentEntry content(this, &fExistingClipStack, fExistingClipRegion, 814 identity, paint); 815 internalDrawPaint(paint, content.entry()); 816 } 817 818 void SkPDFDevice::drawPaint(const SkDraw& d, const SkPaint& paint) { 819 SkPaint newPaint = paint; 820 newPaint.setStyle(SkPaint::kFill_Style); 821 ScopedContentEntry content(this, d, newPaint); 822 internalDrawPaint(newPaint, content.entry()); 823 } 824 825 void SkPDFDevice::internalDrawPaint(const SkPaint& paint, 826 ContentEntry* contentEntry) { 827 if (!contentEntry) { 828 return; 829 } 830 SkRect bbox = SkRect::MakeWH(SkIntToScalar(this->width()), 831 SkIntToScalar(this->height())); 832 SkMatrix inverse; 833 if (!contentEntry->fState.fMatrix.invert(&inverse)) { 834 return; 835 } 836 inverse.mapRect(&bbox); 837 838 SkPDFUtils::AppendRectangle(bbox, &contentEntry->fContent); 839 SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType, 840 &contentEntry->fContent); 841 } 842 843 void SkPDFDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode, 844 size_t count, const SkPoint* points, 845 const SkPaint& passedPaint) { 846 if (count == 0) { 847 return; 848 } 849 850 if (handlePointAnnotation(points, count, *d.fMatrix, passedPaint)) { 851 return; 852 } 853 854 // SkDraw::drawPoints converts to multiple calls to fDevice->drawPath. 855 // We only use this when there's a path effect because of the overhead 856 // of multiple calls to setUpContentEntry it causes. 857 if (passedPaint.getPathEffect()) { 858 if (d.fClip->isEmpty()) { 859 return; 860 } 861 SkDraw pointDraw(d); 862 pointDraw.fDevice = this; 863 pointDraw.drawPoints(mode, count, points, passedPaint, true); 864 return; 865 } 866 867 const SkPaint* paint = &passedPaint; 868 SkPaint modifiedPaint; 869 870 if (mode == SkCanvas::kPoints_PointMode && 871 paint->getStrokeCap() != SkPaint::kRound_Cap) { 872 modifiedPaint = *paint; 873 paint = &modifiedPaint; 874 if (paint->getStrokeWidth()) { 875 // PDF won't draw a single point with square/butt caps because the 876 // orientation is ambiguous. Draw a rectangle instead. 877 modifiedPaint.setStyle(SkPaint::kFill_Style); 878 SkScalar strokeWidth = paint->getStrokeWidth(); 879 SkScalar halfStroke = SkScalarHalf(strokeWidth); 880 for (size_t i = 0; i < count; i++) { 881 SkRect r = SkRect::MakeXYWH(points[i].fX, points[i].fY, 0, 0); 882 r.inset(-halfStroke, -halfStroke); 883 drawRect(d, r, modifiedPaint); 884 } 885 return; 886 } else { 887 modifiedPaint.setStrokeCap(SkPaint::kRound_Cap); 888 } 889 } 890 891 ScopedContentEntry content(this, d, *paint); 892 if (!content.entry()) { 893 return; 894 } 895 896 switch (mode) { 897 case SkCanvas::kPolygon_PointMode: 898 SkPDFUtils::MoveTo(points[0].fX, points[0].fY, 899 &content.entry()->fContent); 900 for (size_t i = 1; i < count; i++) { 901 SkPDFUtils::AppendLine(points[i].fX, points[i].fY, 902 &content.entry()->fContent); 903 } 904 SkPDFUtils::StrokePath(&content.entry()->fContent); 905 break; 906 case SkCanvas::kLines_PointMode: 907 for (size_t i = 0; i < count/2; i++) { 908 SkPDFUtils::MoveTo(points[i * 2].fX, points[i * 2].fY, 909 &content.entry()->fContent); 910 SkPDFUtils::AppendLine(points[i * 2 + 1].fX, 911 points[i * 2 + 1].fY, 912 &content.entry()->fContent); 913 SkPDFUtils::StrokePath(&content.entry()->fContent); 914 } 915 break; 916 case SkCanvas::kPoints_PointMode: 917 SkASSERT(paint->getStrokeCap() == SkPaint::kRound_Cap); 918 for (size_t i = 0; i < count; i++) { 919 SkPDFUtils::MoveTo(points[i].fX, points[i].fY, 920 &content.entry()->fContent); 921 SkPDFUtils::ClosePath(&content.entry()->fContent); 922 SkPDFUtils::StrokePath(&content.entry()->fContent); 923 } 924 break; 925 default: 926 SkASSERT(false); 927 } 928 } 929 930 void SkPDFDevice::drawRect(const SkDraw& d, const SkRect& rect, 931 const SkPaint& paint) { 932 SkRect r = rect; 933 r.sort(); 934 935 if (paint.getPathEffect()) { 936 if (d.fClip->isEmpty()) { 937 return; 938 } 939 SkPath path; 940 path.addRect(r); 941 drawPath(d, path, paint, NULL, true); 942 return; 943 } 944 945 if (handleRectAnnotation(r, *d.fMatrix, paint)) { 946 return; 947 } 948 949 ScopedContentEntry content(this, d, paint); 950 if (!content.entry()) { 951 return; 952 } 953 SkPDFUtils::AppendRectangle(r, &content.entry()->fContent); 954 SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType, 955 &content.entry()->fContent); 956 } 957 958 void SkPDFDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) { 959 SkPath path; 960 path.addRRect(rrect); 961 this->drawPath(draw, path, paint, NULL, true); 962 } 963 964 void SkPDFDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) { 965 SkPath path; 966 path.addOval(oval); 967 this->drawPath(draw, path, paint, NULL, true); 968 } 969 970 void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& origPath, 971 const SkPaint& paint, const SkMatrix* prePathMatrix, 972 bool pathIsMutable) { 973 SkPath modifiedPath; 974 SkPath* pathPtr = const_cast<SkPath*>(&origPath); 975 976 SkMatrix matrix = *d.fMatrix; 977 if (prePathMatrix) { 978 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) { 979 if (!pathIsMutable) { 980 pathPtr = &modifiedPath; 981 pathIsMutable = true; 982 } 983 origPath.transform(*prePathMatrix, pathPtr); 984 } else { 985 matrix.preConcat(*prePathMatrix); 986 } 987 } 988 989 if (paint.getPathEffect()) { 990 if (d.fClip->isEmpty()) { 991 return; 992 } 993 if (!pathIsMutable) { 994 pathPtr = &modifiedPath; 995 pathIsMutable = true; 996 } 997 bool fill = paint.getFillPath(origPath, pathPtr); 998 999 SkPaint noEffectPaint(paint); 1000 noEffectPaint.setPathEffect(NULL); 1001 if (fill) { 1002 noEffectPaint.setStyle(SkPaint::kFill_Style); 1003 } else { 1004 noEffectPaint.setStyle(SkPaint::kStroke_Style); 1005 noEffectPaint.setStrokeWidth(0); 1006 } 1007 drawPath(d, *pathPtr, noEffectPaint, NULL, true); 1008 return; 1009 } 1010 1011 #ifdef SK_PDF_USE_PATHOPS 1012 if (handleInversePath(d, origPath, paint, pathIsMutable, prePathMatrix)) { 1013 return; 1014 } 1015 #endif 1016 1017 if (handleRectAnnotation(pathPtr->getBounds(), matrix, paint)) { 1018 return; 1019 } 1020 1021 ScopedContentEntry content(this, d.fClipStack, *d.fClip, matrix, paint); 1022 if (!content.entry()) { 1023 return; 1024 } 1025 SkPDFUtils::EmitPath(*pathPtr, paint.getStyle(), 1026 &content.entry()->fContent); 1027 SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(), 1028 &content.entry()->fContent); 1029 } 1030 1031 void SkPDFDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, 1032 const SkRect* src, const SkRect& dst, 1033 const SkPaint& paint, 1034 SkCanvas::DrawBitmapRectFlags flags) { 1035 // TODO: this code path must be updated to respect the flags parameter 1036 SkMatrix matrix; 1037 SkRect bitmapBounds, tmpSrc, tmpDst; 1038 SkBitmap tmpBitmap; 1039 1040 bitmapBounds.isetWH(bitmap.width(), bitmap.height()); 1041 1042 // Compute matrix from the two rectangles 1043 if (src) { 1044 tmpSrc = *src; 1045 } else { 1046 tmpSrc = bitmapBounds; 1047 } 1048 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); 1049 1050 const SkBitmap* bitmapPtr = &bitmap; 1051 1052 // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if 1053 // needed (if the src was clipped). No check needed if src==null. 1054 if (src) { 1055 if (!bitmapBounds.contains(*src)) { 1056 if (!tmpSrc.intersect(bitmapBounds)) { 1057 return; // nothing to draw 1058 } 1059 // recompute dst, based on the smaller tmpSrc 1060 matrix.mapRect(&tmpDst, tmpSrc); 1061 } 1062 1063 // since we may need to clamp to the borders of the src rect within 1064 // the bitmap, we extract a subset. 1065 // TODO: make sure this is handled in drawBitmap and remove from here. 1066 SkIRect srcIR; 1067 tmpSrc.roundOut(&srcIR); 1068 if (!bitmap.extractSubset(&tmpBitmap, srcIR)) { 1069 return; 1070 } 1071 bitmapPtr = &tmpBitmap; 1072 1073 // Since we did an extract, we need to adjust the matrix accordingly 1074 SkScalar dx = 0, dy = 0; 1075 if (srcIR.fLeft > 0) { 1076 dx = SkIntToScalar(srcIR.fLeft); 1077 } 1078 if (srcIR.fTop > 0) { 1079 dy = SkIntToScalar(srcIR.fTop); 1080 } 1081 if (dx || dy) { 1082 matrix.preTranslate(dx, dy); 1083 } 1084 } 1085 this->drawBitmap(draw, *bitmapPtr, matrix, paint); 1086 } 1087 1088 void SkPDFDevice::drawBitmap(const SkDraw& d, const SkBitmap& bitmap, 1089 const SkMatrix& matrix, const SkPaint& paint) { 1090 if (d.fClip->isEmpty()) { 1091 return; 1092 } 1093 1094 SkMatrix transform = matrix; 1095 transform.postConcat(*d.fMatrix); 1096 this->internalDrawBitmap(transform, d.fClipStack, *d.fClip, bitmap, NULL, 1097 paint); 1098 } 1099 1100 void SkPDFDevice::drawSprite(const SkDraw& d, const SkBitmap& bitmap, 1101 int x, int y, const SkPaint& paint) { 1102 if (d.fClip->isEmpty()) { 1103 return; 1104 } 1105 1106 SkMatrix matrix; 1107 matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y)); 1108 this->internalDrawBitmap(matrix, d.fClipStack, *d.fClip, bitmap, NULL, 1109 paint); 1110 } 1111 1112 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, 1113 SkScalar x, SkScalar y, const SkPaint& paint) { 1114 NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false); 1115 if (paint.getMaskFilter() != NULL) { 1116 // Don't pretend we support drawing MaskFilters, it makes for artifacts 1117 // making text unreadable (e.g. same text twice when using CSS shadows). 1118 return; 1119 } 1120 SkPaint textPaint = calculate_text_paint(paint); 1121 ScopedContentEntry content(this, d, textPaint, true); 1122 if (!content.entry()) { 1123 return; 1124 } 1125 1126 SkGlyphStorage storage(0); 1127 const uint16_t* glyphIDs = NULL; 1128 int numGlyphs = force_glyph_encoding(paint, text, len, &storage, &glyphIDs); 1129 textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 1130 1131 SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc(); 1132 align_text(glyphCacheProc, textPaint, glyphIDs, numGlyphs, &x, &y); 1133 content.entry()->fContent.writeText("BT\n"); 1134 set_text_transform(x, y, textPaint.getTextSkewX(), 1135 &content.entry()->fContent); 1136 int consumedGlyphCount = 0; 1137 while (numGlyphs > consumedGlyphCount) { 1138 updateFont(textPaint, glyphIDs[consumedGlyphCount], content.entry()); 1139 SkPDFFont* font = content.entry()->fState.fFont; 1140 //TODO: the const_cast here is a bug if the encoding started out as glyph encoding. 1141 int availableGlyphs = 1142 font->glyphsToPDFFontEncoding(const_cast<uint16_t*>(glyphIDs) + consumedGlyphCount, 1143 numGlyphs - consumedGlyphCount); 1144 fFontGlyphUsage->noteGlyphUsage(font, glyphIDs + consumedGlyphCount, 1145 availableGlyphs); 1146 SkString encodedString = 1147 SkPDFString::FormatString(glyphIDs + consumedGlyphCount, 1148 availableGlyphs, font->multiByteGlyphs()); 1149 content.entry()->fContent.writeText(encodedString.c_str()); 1150 consumedGlyphCount += availableGlyphs; 1151 content.entry()->fContent.writeText(" Tj\n"); 1152 } 1153 content.entry()->fContent.writeText("ET\n"); 1154 } 1155 1156 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, 1157 const SkScalar pos[], SkScalar constY, 1158 int scalarsPerPos, const SkPaint& paint) { 1159 NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false); 1160 if (paint.getMaskFilter() != NULL) { 1161 // Don't pretend we support drawing MaskFilters, it makes for artifacts 1162 // making text unreadable (e.g. same text twice when using CSS shadows). 1163 return; 1164 } 1165 SkASSERT(1 == scalarsPerPos || 2 == scalarsPerPos); 1166 SkPaint textPaint = calculate_text_paint(paint); 1167 ScopedContentEntry content(this, d, textPaint, true); 1168 if (!content.entry()) { 1169 return; 1170 } 1171 1172 SkGlyphStorage storage(0); 1173 const uint16_t* glyphIDs = NULL; 1174 size_t numGlyphs = force_glyph_encoding(paint, text, len, &storage, &glyphIDs); 1175 textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 1176 1177 SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc(); 1178 content.entry()->fContent.writeText("BT\n"); 1179 updateFont(textPaint, glyphIDs[0], content.entry()); 1180 for (size_t i = 0; i < numGlyphs; i++) { 1181 SkPDFFont* font = content.entry()->fState.fFont; 1182 uint16_t encodedValue = glyphIDs[i]; 1183 if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) { 1184 // The current pdf font cannot encode the current glyph. 1185 // Try to get a pdf font which can encode the current glyph. 1186 updateFont(textPaint, glyphIDs[i], content.entry()); 1187 font = content.entry()->fState.fFont; 1188 if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) { 1189 SkDEBUGFAIL("PDF could not encode glyph."); 1190 continue; 1191 } 1192 } 1193 1194 fFontGlyphUsage->noteGlyphUsage(font, &encodedValue, 1); 1195 SkScalar x = pos[i * scalarsPerPos]; 1196 SkScalar y = scalarsPerPos == 1 ? constY : pos[i * scalarsPerPos + 1]; 1197 align_text(glyphCacheProc, textPaint, glyphIDs + i, 1, &x, &y); 1198 set_text_transform(x, y, textPaint.getTextSkewX(), &content.entry()->fContent); 1199 SkString encodedString = 1200 SkPDFString::FormatString(&encodedValue, 1, font->multiByteGlyphs()); 1201 content.entry()->fContent.writeText(encodedString.c_str()); 1202 content.entry()->fContent.writeText(" Tj\n"); 1203 } 1204 content.entry()->fContent.writeText("ET\n"); 1205 } 1206 1207 void SkPDFDevice::drawTextOnPath(const SkDraw& d, const void* text, size_t len, 1208 const SkPath& path, const SkMatrix* matrix, 1209 const SkPaint& paint) { 1210 if (d.fClip->isEmpty()) { 1211 return; 1212 } 1213 d.drawTextOnPath((const char*)text, len, path, matrix, paint); 1214 } 1215 1216 void SkPDFDevice::drawVertices(const SkDraw& d, SkCanvas::VertexMode, 1217 int vertexCount, const SkPoint verts[], 1218 const SkPoint texs[], const SkColor colors[], 1219 SkXfermode* xmode, const uint16_t indices[], 1220 int indexCount, const SkPaint& paint) { 1221 if (d.fClip->isEmpty()) { 1222 return; 1223 } 1224 // TODO: implement drawVertices 1225 } 1226 1227 void SkPDFDevice::drawDevice(const SkDraw& d, SkBaseDevice* device, 1228 int x, int y, const SkPaint& paint) { 1229 // our onCreateDevice() always creates SkPDFDevice subclasses. 1230 SkPDFDevice* pdfDevice = static_cast<SkPDFDevice*>(device); 1231 if (pdfDevice->isContentEmpty()) { 1232 return; 1233 } 1234 1235 SkMatrix matrix; 1236 matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y)); 1237 ScopedContentEntry content(this, d.fClipStack, *d.fClip, matrix, paint); 1238 if (!content.entry()) { 1239 return; 1240 } 1241 if (content.needShape()) { 1242 SkPath shape; 1243 shape.addRect(SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y), 1244 SkIntToScalar(device->width()), 1245 SkIntToScalar(device->height()))); 1246 content.setShape(shape); 1247 } 1248 if (!content.needSource()) { 1249 return; 1250 } 1251 1252 SkAutoTUnref<SkPDFFormXObject> xObject(new SkPDFFormXObject(pdfDevice)); 1253 SkPDFUtils::DrawFormXObject(this->addXObjectResource(xObject.get()), 1254 &content.entry()->fContent); 1255 1256 // Merge glyph sets from the drawn device. 1257 fFontGlyphUsage->merge(pdfDevice->getFontGlyphUsage()); 1258 } 1259 1260 SkImageInfo SkPDFDevice::imageInfo() const { 1261 return fLegacyBitmap.info(); 1262 } 1263 1264 void SkPDFDevice::onAttachToCanvas(SkCanvas* canvas) { 1265 INHERITED::onAttachToCanvas(canvas); 1266 1267 // Canvas promises that this ptr is valid until onDetachFromCanvas is called 1268 fClipStack = canvas->getClipStack(); 1269 } 1270 1271 void SkPDFDevice::onDetachFromCanvas() { 1272 INHERITED::onDetachFromCanvas(); 1273 1274 fClipStack = NULL; 1275 } 1276 1277 SkSurface* SkPDFDevice::newSurface(const SkImageInfo& info, const SkSurfaceProps& props) { 1278 return SkSurface::NewRaster(info, &props); 1279 } 1280 1281 ContentEntry* SkPDFDevice::getLastContentEntry() { 1282 if (fDrawingArea == kContent_DrawingArea) { 1283 return fLastContentEntry; 1284 } else { 1285 return fLastMarginContentEntry; 1286 } 1287 } 1288 1289 SkAutoTDelete<ContentEntry>* SkPDFDevice::getContentEntries() { 1290 if (fDrawingArea == kContent_DrawingArea) { 1291 return &fContentEntries; 1292 } else { 1293 return &fMarginContentEntries; 1294 } 1295 } 1296 1297 void SkPDFDevice::setLastContentEntry(ContentEntry* contentEntry) { 1298 if (fDrawingArea == kContent_DrawingArea) { 1299 fLastContentEntry = contentEntry; 1300 } else { 1301 fLastMarginContentEntry = contentEntry; 1302 } 1303 } 1304 1305 void SkPDFDevice::setDrawingArea(DrawingArea drawingArea) { 1306 // A ScopedContentEntry only exists during the course of a draw call, so 1307 // this can't be called while a ScopedContentEntry exists. 1308 fDrawingArea = drawingArea; 1309 } 1310 1311 SkPDFResourceDict* SkPDFDevice::getResourceDict() { 1312 if (NULL == fResourceDict) { 1313 fResourceDict = SkNEW(SkPDFResourceDict); 1314 1315 if (fGraphicStateResources.count()) { 1316 for (int i = 0; i < fGraphicStateResources.count(); i++) { 1317 fResourceDict->insertResourceAsReference( 1318 SkPDFResourceDict::kExtGState_ResourceType, 1319 i, fGraphicStateResources[i]); 1320 } 1321 } 1322 1323 if (fXObjectResources.count()) { 1324 for (int i = 0; i < fXObjectResources.count(); i++) { 1325 fResourceDict->insertResourceAsReference( 1326 SkPDFResourceDict::kXObject_ResourceType, 1327 i, fXObjectResources[i]); 1328 } 1329 } 1330 1331 if (fFontResources.count()) { 1332 for (int i = 0; i < fFontResources.count(); i++) { 1333 fResourceDict->insertResourceAsReference( 1334 SkPDFResourceDict::kFont_ResourceType, 1335 i, fFontResources[i]); 1336 } 1337 } 1338 1339 if (fShaderResources.count()) { 1340 SkAutoTUnref<SkPDFDict> patterns(new SkPDFDict()); 1341 for (int i = 0; i < fShaderResources.count(); i++) { 1342 fResourceDict->insertResourceAsReference( 1343 SkPDFResourceDict::kPattern_ResourceType, 1344 i, fShaderResources[i]); 1345 } 1346 } 1347 } 1348 return fResourceDict; 1349 } 1350 1351 const SkTDArray<SkPDFFont*>& SkPDFDevice::getFontResources() const { 1352 return fFontResources; 1353 } 1354 1355 SkPDFArray* SkPDFDevice::copyMediaBox() const { 1356 // should this be a singleton? 1357 SkAutoTUnref<SkPDFInt> zero(SkNEW_ARGS(SkPDFInt, (0))); 1358 1359 SkPDFArray* mediaBox = SkNEW(SkPDFArray); 1360 mediaBox->reserve(4); 1361 mediaBox->append(zero.get()); 1362 mediaBox->append(zero.get()); 1363 mediaBox->appendInt(fPageSize.fWidth); 1364 mediaBox->appendInt(fPageSize.fHeight); 1365 return mediaBox; 1366 } 1367 1368 SkStream* SkPDFDevice::content() const { 1369 SkMemoryStream* result = new SkMemoryStream; 1370 result->setData(this->copyContentToData())->unref(); 1371 return result; 1372 } 1373 1374 void SkPDFDevice::copyContentEntriesToData(ContentEntry* entry, 1375 SkWStream* data) const { 1376 // TODO(ctguil): For margins, I'm not sure fExistingClipStack/Region is the 1377 // right thing to pass here. 1378 GraphicStackState gsState(fExistingClipStack, fExistingClipRegion, data); 1379 while (entry != NULL) { 1380 SkPoint translation; 1381 translation.iset(this->getOrigin()); 1382 translation.negate(); 1383 gsState.updateClip(entry->fState.fClipStack, entry->fState.fClipRegion, 1384 translation); 1385 gsState.updateMatrix(entry->fState.fMatrix); 1386 gsState.updateDrawingState(entry->fState); 1387 1388 SkAutoDataUnref copy(entry->fContent.copyToData()); 1389 data->write(copy->data(), copy->size()); 1390 entry = entry->fNext.get(); 1391 } 1392 gsState.drainStack(); 1393 } 1394 1395 SkData* SkPDFDevice::copyContentToData() const { 1396 SkDynamicMemoryWStream data; 1397 if (fInitialTransform.getType() != SkMatrix::kIdentity_Mask) { 1398 SkPDFUtils::AppendTransform(fInitialTransform, &data); 1399 } 1400 1401 // TODO(aayushkumar): Apply clip along the margins. Currently, webkit 1402 // colors the contentArea white before it starts drawing into it and 1403 // that currently acts as our clip. 1404 // Also, think about adding a transform here (or assume that the values 1405 // sent across account for that) 1406 SkPDFDevice::copyContentEntriesToData(fMarginContentEntries.get(), &data); 1407 1408 // If the content area is the entire page, then we don't need to clip 1409 // the content area (PDF area clips to the page size). Otherwise, 1410 // we have to clip to the content area; we've already applied the 1411 // initial transform, so just clip to the device size. 1412 if (fPageSize != fContentSize) { 1413 SkRect r = SkRect::MakeWH(SkIntToScalar(this->width()), 1414 SkIntToScalar(this->height())); 1415 emit_clip(NULL, &r, &data); 1416 } 1417 1418 SkPDFDevice::copyContentEntriesToData(fContentEntries.get(), &data); 1419 1420 // potentially we could cache this SkData, and only rebuild it if we 1421 // see that our state has changed. 1422 return data.copyToData(); 1423 } 1424 1425 #ifdef SK_PDF_USE_PATHOPS 1426 /* Draws an inverse filled path by using Path Ops to compute the positive 1427 * inverse using the current clip as the inverse bounds. 1428 * Return true if this was an inverse path and was properly handled, 1429 * otherwise returns false and the normal drawing routine should continue, 1430 * either as a (incorrect) fallback or because the path was not inverse 1431 * in the first place. 1432 */ 1433 bool SkPDFDevice::handleInversePath(const SkDraw& d, const SkPath& origPath, 1434 const SkPaint& paint, bool pathIsMutable, 1435 const SkMatrix* prePathMatrix) { 1436 if (!origPath.isInverseFillType()) { 1437 return false; 1438 } 1439 1440 if (d.fClip->isEmpty()) { 1441 return false; 1442 } 1443 1444 SkPath modifiedPath; 1445 SkPath* pathPtr = const_cast<SkPath*>(&origPath); 1446 SkPaint noInversePaint(paint); 1447 1448 // Merge stroking operations into final path. 1449 if (SkPaint::kStroke_Style == paint.getStyle() || 1450 SkPaint::kStrokeAndFill_Style == paint.getStyle()) { 1451 bool doFillPath = paint.getFillPath(origPath, &modifiedPath); 1452 if (doFillPath) { 1453 noInversePaint.setStyle(SkPaint::kFill_Style); 1454 noInversePaint.setStrokeWidth(0); 1455 pathPtr = &modifiedPath; 1456 } else { 1457 // To be consistent with the raster output, hairline strokes 1458 // are rendered as non-inverted. 1459 modifiedPath.toggleInverseFillType(); 1460 drawPath(d, modifiedPath, paint, NULL, true); 1461 return true; 1462 } 1463 } 1464 1465 // Get bounds of clip in current transform space 1466 // (clip bounds are given in device space). 1467 SkRect bounds; 1468 SkMatrix transformInverse; 1469 SkMatrix totalMatrix = *d.fMatrix; 1470 if (prePathMatrix) { 1471 totalMatrix.preConcat(*prePathMatrix); 1472 } 1473 if (!totalMatrix.invert(&transformInverse)) { 1474 return false; 1475 } 1476 bounds.set(d.fClip->getBounds()); 1477 transformInverse.mapRect(&bounds); 1478 1479 // Extend the bounds by the line width (plus some padding) 1480 // so the edge doesn't cause a visible stroke. 1481 bounds.outset(paint.getStrokeWidth() + SK_Scalar1, 1482 paint.getStrokeWidth() + SK_Scalar1); 1483 1484 if (!calculate_inverse_path(bounds, *pathPtr, &modifiedPath)) { 1485 return false; 1486 } 1487 1488 drawPath(d, modifiedPath, noInversePaint, prePathMatrix, true); 1489 return true; 1490 } 1491 #endif 1492 1493 bool SkPDFDevice::handleRectAnnotation(const SkRect& r, const SkMatrix& matrix, 1494 const SkPaint& p) { 1495 SkAnnotation* annotationInfo = p.getAnnotation(); 1496 if (!annotationInfo) { 1497 return false; 1498 } 1499 SkData* urlData = annotationInfo->find(SkAnnotationKeys::URL_Key()); 1500 if (urlData) { 1501 handleLinkToURL(urlData, r, matrix); 1502 return p.getAnnotation() != NULL; 1503 } 1504 SkData* linkToName = annotationInfo->find( 1505 SkAnnotationKeys::Link_Named_Dest_Key()); 1506 if (linkToName) { 1507 handleLinkToNamedDest(linkToName, r, matrix); 1508 return p.getAnnotation() != NULL; 1509 } 1510 return false; 1511 } 1512 1513 bool SkPDFDevice::handlePointAnnotation(const SkPoint* points, size_t count, 1514 const SkMatrix& matrix, 1515 const SkPaint& paint) { 1516 SkAnnotation* annotationInfo = paint.getAnnotation(); 1517 if (!annotationInfo) { 1518 return false; 1519 } 1520 SkData* nameData = annotationInfo->find( 1521 SkAnnotationKeys::Define_Named_Dest_Key()); 1522 if (nameData) { 1523 for (size_t i = 0; i < count; i++) { 1524 defineNamedDestination(nameData, points[i], matrix); 1525 } 1526 return paint.getAnnotation() != NULL; 1527 } 1528 return false; 1529 } 1530 1531 SkPDFDict* SkPDFDevice::createLinkAnnotation(const SkRect& r, 1532 const SkMatrix& matrix) { 1533 SkMatrix transform = matrix; 1534 transform.postConcat(fInitialTransform); 1535 SkRect translatedRect; 1536 transform.mapRect(&translatedRect, r); 1537 1538 if (NULL == fAnnotations) { 1539 fAnnotations = SkNEW(SkPDFArray); 1540 } 1541 SkPDFDict* annotation(SkNEW_ARGS(SkPDFDict, ("Annot"))); 1542 annotation->insertName("Subtype", "Link"); 1543 fAnnotations->append(annotation); 1544 1545 SkAutoTUnref<SkPDFArray> border(SkNEW(SkPDFArray)); 1546 border->reserve(3); 1547 border->appendInt(0); // Horizontal corner radius. 1548 border->appendInt(0); // Vertical corner radius. 1549 border->appendInt(0); // Width, 0 = no border. 1550 annotation->insert("Border", border.get()); 1551 1552 SkAutoTUnref<SkPDFArray> rect(SkNEW(SkPDFArray)); 1553 rect->reserve(4); 1554 rect->appendScalar(translatedRect.fLeft); 1555 rect->appendScalar(translatedRect.fTop); 1556 rect->appendScalar(translatedRect.fRight); 1557 rect->appendScalar(translatedRect.fBottom); 1558 annotation->insert("Rect", rect.get()); 1559 1560 return annotation; 1561 } 1562 1563 void SkPDFDevice::handleLinkToURL(SkData* urlData, const SkRect& r, 1564 const SkMatrix& matrix) { 1565 SkAutoTUnref<SkPDFDict> annotation(createLinkAnnotation(r, matrix)); 1566 1567 SkString url(static_cast<const char *>(urlData->data()), 1568 urlData->size() - 1); 1569 SkAutoTUnref<SkPDFDict> action(SkNEW_ARGS(SkPDFDict, ("Action"))); 1570 action->insertName("S", "URI"); 1571 action->insert("URI", SkNEW_ARGS(SkPDFString, (url)))->unref(); 1572 annotation->insert("A", action.get()); 1573 } 1574 1575 void SkPDFDevice::handleLinkToNamedDest(SkData* nameData, const SkRect& r, 1576 const SkMatrix& matrix) { 1577 SkAutoTUnref<SkPDFDict> annotation(createLinkAnnotation(r, matrix)); 1578 SkString name(static_cast<const char *>(nameData->data()), 1579 nameData->size() - 1); 1580 annotation->insert("Dest", SkNEW_ARGS(SkPDFName, (name)))->unref(); 1581 } 1582 1583 struct NamedDestination { 1584 const SkData* nameData; 1585 SkPoint point; 1586 1587 NamedDestination(const SkData* nameData, const SkPoint& point) 1588 : nameData(nameData), point(point) { 1589 nameData->ref(); 1590 } 1591 1592 ~NamedDestination() { 1593 nameData->unref(); 1594 } 1595 }; 1596 1597 void SkPDFDevice::defineNamedDestination(SkData* nameData, const SkPoint& point, 1598 const SkMatrix& matrix) { 1599 SkMatrix transform = matrix; 1600 transform.postConcat(fInitialTransform); 1601 SkPoint translatedPoint; 1602 transform.mapXY(point.x(), point.y(), &translatedPoint); 1603 fNamedDestinations.push( 1604 SkNEW_ARGS(NamedDestination, (nameData, translatedPoint))); 1605 } 1606 1607 void SkPDFDevice::appendDestinations(SkPDFDict* dict, SkPDFObject* page) { 1608 int nDest = fNamedDestinations.count(); 1609 for (int i = 0; i < nDest; i++) { 1610 NamedDestination* dest = fNamedDestinations[i]; 1611 SkAutoTUnref<SkPDFArray> pdfDest(SkNEW(SkPDFArray)); 1612 pdfDest->reserve(5); 1613 pdfDest->append(SkNEW_ARGS(SkPDFObjRef, (page)))->unref(); 1614 pdfDest->appendName("XYZ"); 1615 pdfDest->appendScalar(dest->point.x()); 1616 pdfDest->appendScalar(dest->point.y()); 1617 pdfDest->appendInt(0); // Leave zoom unchanged 1618 dict->insert(static_cast<const char *>(dest->nameData->data()), 1619 pdfDest); 1620 } 1621 } 1622 1623 SkPDFFormXObject* SkPDFDevice::createFormXObjectFromDevice() { 1624 SkPDFFormXObject* xobject = SkNEW_ARGS(SkPDFFormXObject, (this)); 1625 // We always draw the form xobjects that we create back into the device, so 1626 // we simply preserve the font usage instead of pulling it out and merging 1627 // it back in later. 1628 cleanUp(false); // Reset this device to have no content. 1629 init(); 1630 return xobject; 1631 } 1632 1633 void SkPDFDevice::drawFormXObjectWithMask(int xObjectIndex, 1634 SkPDFFormXObject* mask, 1635 const SkClipStack* clipStack, 1636 const SkRegion& clipRegion, 1637 SkXfermode::Mode mode, 1638 bool invertClip) { 1639 if (clipRegion.isEmpty() && !invertClip) { 1640 return; 1641 } 1642 1643 SkAutoTUnref<SkPDFGraphicState> sMaskGS( 1644 SkPDFGraphicState::GetSMaskGraphicState( 1645 mask, invertClip, SkPDFGraphicState::kAlpha_SMaskMode)); 1646 1647 SkMatrix identity; 1648 identity.reset(); 1649 SkPaint paint; 1650 paint.setXfermodeMode(mode); 1651 ScopedContentEntry content(this, clipStack, clipRegion, identity, paint); 1652 if (!content.entry()) { 1653 return; 1654 } 1655 SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()), 1656 &content.entry()->fContent); 1657 SkPDFUtils::DrawFormXObject(xObjectIndex, &content.entry()->fContent); 1658 1659 sMaskGS.reset(SkPDFGraphicState::GetNoSMaskGraphicState()); 1660 SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()), 1661 &content.entry()->fContent); 1662 } 1663 1664 ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack, 1665 const SkRegion& clipRegion, 1666 const SkMatrix& matrix, 1667 const SkPaint& paint, 1668 bool hasText, 1669 SkPDFFormXObject** dst) { 1670 *dst = NULL; 1671 if (clipRegion.isEmpty()) { 1672 return NULL; 1673 } 1674 1675 // The clip stack can come from an SkDraw where it is technically optional. 1676 SkClipStack synthesizedClipStack; 1677 if (clipStack == NULL) { 1678 if (clipRegion == fExistingClipRegion) { 1679 clipStack = &fExistingClipStack; 1680 } else { 1681 // GraphicStackState::updateClip expects the clip stack to have 1682 // fExistingClip as a prefix, so start there, then set the clip 1683 // to the passed region. 1684 synthesizedClipStack = fExistingClipStack; 1685 SkPath clipPath; 1686 clipRegion.getBoundaryPath(&clipPath); 1687 synthesizedClipStack.clipDevPath(clipPath, SkRegion::kReplace_Op, 1688 false); 1689 clipStack = &synthesizedClipStack; 1690 } 1691 } 1692 1693 SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode; 1694 if (paint.getXfermode()) { 1695 paint.getXfermode()->asMode(&xfermode); 1696 } 1697 1698 // For the following modes, we want to handle source and destination 1699 // separately, so make an object of what's already there. 1700 if (xfermode == SkXfermode::kClear_Mode || 1701 xfermode == SkXfermode::kSrc_Mode || 1702 xfermode == SkXfermode::kSrcIn_Mode || 1703 xfermode == SkXfermode::kDstIn_Mode || 1704 xfermode == SkXfermode::kSrcOut_Mode || 1705 xfermode == SkXfermode::kDstOut_Mode || 1706 xfermode == SkXfermode::kSrcATop_Mode || 1707 xfermode == SkXfermode::kDstATop_Mode || 1708 xfermode == SkXfermode::kModulate_Mode) { 1709 if (!isContentEmpty()) { 1710 *dst = createFormXObjectFromDevice(); 1711 SkASSERT(isContentEmpty()); 1712 } else if (xfermode != SkXfermode::kSrc_Mode && 1713 xfermode != SkXfermode::kSrcOut_Mode) { 1714 // Except for Src and SrcOut, if there isn't anything already there, 1715 // then we're done. 1716 return NULL; 1717 } 1718 } 1719 // TODO(vandebo): Figure out how/if we can handle the following modes: 1720 // Xor, Plus. 1721 1722 // Dst xfer mode doesn't draw source at all. 1723 if (xfermode == SkXfermode::kDst_Mode) { 1724 return NULL; 1725 } 1726 1727 ContentEntry* entry; 1728 SkAutoTDelete<ContentEntry> newEntry; 1729 1730 ContentEntry* lastContentEntry = getLastContentEntry(); 1731 if (lastContentEntry && lastContentEntry->fContent.getOffset() == 0) { 1732 entry = lastContentEntry; 1733 } else { 1734 newEntry.reset(new ContentEntry); 1735 entry = newEntry.get(); 1736 } 1737 1738 populateGraphicStateEntryFromPaint(matrix, *clipStack, clipRegion, paint, 1739 hasText, &entry->fState); 1740 if (lastContentEntry && xfermode != SkXfermode::kDstOver_Mode && 1741 entry->fState.compareInitialState(lastContentEntry->fState)) { 1742 return lastContentEntry; 1743 } 1744 1745 SkAutoTDelete<ContentEntry>* contentEntries = getContentEntries(); 1746 if (!lastContentEntry) { 1747 contentEntries->reset(entry); 1748 setLastContentEntry(entry); 1749 } else if (xfermode == SkXfermode::kDstOver_Mode) { 1750 entry->fNext.reset(contentEntries->detach()); 1751 contentEntries->reset(entry); 1752 } else { 1753 lastContentEntry->fNext.reset(entry); 1754 setLastContentEntry(entry); 1755 } 1756 newEntry.detach(); 1757 return entry; 1758 } 1759 1760 void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode, 1761 SkPDFFormXObject* dst, 1762 SkPath* shape) { 1763 if (xfermode != SkXfermode::kClear_Mode && 1764 xfermode != SkXfermode::kSrc_Mode && 1765 xfermode != SkXfermode::kDstOver_Mode && 1766 xfermode != SkXfermode::kSrcIn_Mode && 1767 xfermode != SkXfermode::kDstIn_Mode && 1768 xfermode != SkXfermode::kSrcOut_Mode && 1769 xfermode != SkXfermode::kDstOut_Mode && 1770 xfermode != SkXfermode::kSrcATop_Mode && 1771 xfermode != SkXfermode::kDstATop_Mode && 1772 xfermode != SkXfermode::kModulate_Mode) { 1773 SkASSERT(!dst); 1774 return; 1775 } 1776 if (xfermode == SkXfermode::kDstOver_Mode) { 1777 SkASSERT(!dst); 1778 ContentEntry* firstContentEntry = getContentEntries()->get(); 1779 if (firstContentEntry->fContent.getOffset() == 0) { 1780 // For DstOver, an empty content entry was inserted before the rest 1781 // of the content entries. If nothing was drawn, it needs to be 1782 // removed. 1783 SkAutoTDelete<ContentEntry>* contentEntries = getContentEntries(); 1784 contentEntries->reset(firstContentEntry->fNext.detach()); 1785 } 1786 return; 1787 } 1788 if (!dst) { 1789 SkASSERT(xfermode == SkXfermode::kSrc_Mode || 1790 xfermode == SkXfermode::kSrcOut_Mode); 1791 return; 1792 } 1793 1794 ContentEntry* contentEntries = getContentEntries()->get(); 1795 SkASSERT(dst); 1796 SkASSERT(!contentEntries->fNext.get()); 1797 // Changing the current content into a form-xobject will destroy the clip 1798 // objects which is fine since the xobject will already be clipped. However 1799 // if source has shape, we need to clip it too, so a copy of the clip is 1800 // saved. 1801 SkClipStack clipStack = contentEntries->fState.fClipStack; 1802 SkRegion clipRegion = contentEntries->fState.fClipRegion; 1803 1804 SkMatrix identity; 1805 identity.reset(); 1806 SkPaint stockPaint; 1807 1808 SkAutoTUnref<SkPDFFormXObject> srcFormXObject; 1809 if (isContentEmpty()) { 1810 // If nothing was drawn and there's no shape, then the draw was a 1811 // no-op, but dst needs to be restored for that to be true. 1812 // If there is shape, then an empty source with Src, SrcIn, SrcOut, 1813 // DstIn, DstAtop or Modulate reduces to Clear and DstOut or SrcAtop 1814 // reduces to Dst. 1815 if (shape == NULL || xfermode == SkXfermode::kDstOut_Mode || 1816 xfermode == SkXfermode::kSrcATop_Mode) { 1817 ScopedContentEntry content(this, &fExistingClipStack, 1818 fExistingClipRegion, identity, 1819 stockPaint); 1820 SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst), 1821 &content.entry()->fContent); 1822 return; 1823 } else { 1824 xfermode = SkXfermode::kClear_Mode; 1825 } 1826 } else { 1827 SkASSERT(!fContentEntries->fNext.get()); 1828 srcFormXObject.reset(createFormXObjectFromDevice()); 1829 } 1830 1831 // TODO(vandebo) srcFormXObject may contain alpha, but here we want it 1832 // without alpha. 1833 if (xfermode == SkXfermode::kSrcATop_Mode) { 1834 // TODO(vandebo): In order to properly support SrcATop we have to track 1835 // the shape of what's been drawn at all times. It's the intersection of 1836 // the non-transparent parts of the device and the outlines (shape) of 1837 // all images and devices drawn. 1838 drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), dst, 1839 &fExistingClipStack, fExistingClipRegion, 1840 SkXfermode::kSrcOver_Mode, true); 1841 } else { 1842 SkAutoTUnref<SkPDFFormXObject> dstMaskStorage; 1843 SkPDFFormXObject* dstMask = srcFormXObject.get(); 1844 if (shape != NULL) { 1845 // Draw shape into a form-xobject. 1846 SkDraw d; 1847 d.fMatrix = &identity; 1848 d.fClip = &clipRegion; 1849 d.fClipStack = &clipStack; 1850 SkPaint filledPaint; 1851 filledPaint.setColor(SK_ColorBLACK); 1852 filledPaint.setStyle(SkPaint::kFill_Style); 1853 this->drawPath(d, *shape, filledPaint, NULL, true); 1854 1855 dstMaskStorage.reset(createFormXObjectFromDevice()); 1856 dstMask = dstMaskStorage.get(); 1857 } 1858 drawFormXObjectWithMask(addXObjectResource(dst), dstMask, 1859 &fExistingClipStack, fExistingClipRegion, 1860 SkXfermode::kSrcOver_Mode, true); 1861 } 1862 1863 if (xfermode == SkXfermode::kClear_Mode) { 1864 return; 1865 } else if (xfermode == SkXfermode::kSrc_Mode || 1866 xfermode == SkXfermode::kDstATop_Mode) { 1867 ScopedContentEntry content(this, &fExistingClipStack, 1868 fExistingClipRegion, identity, stockPaint); 1869 if (content.entry()) { 1870 SkPDFUtils::DrawFormXObject( 1871 this->addXObjectResource(srcFormXObject.get()), 1872 &content.entry()->fContent); 1873 } 1874 if (xfermode == SkXfermode::kSrc_Mode) { 1875 return; 1876 } 1877 } else if (xfermode == SkXfermode::kSrcATop_Mode) { 1878 ScopedContentEntry content(this, &fExistingClipStack, 1879 fExistingClipRegion, identity, stockPaint); 1880 if (content.entry()) { 1881 SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst), 1882 &content.entry()->fContent); 1883 } 1884 } 1885 1886 SkASSERT(xfermode == SkXfermode::kSrcIn_Mode || 1887 xfermode == SkXfermode::kDstIn_Mode || 1888 xfermode == SkXfermode::kSrcOut_Mode || 1889 xfermode == SkXfermode::kDstOut_Mode || 1890 xfermode == SkXfermode::kSrcATop_Mode || 1891 xfermode == SkXfermode::kDstATop_Mode || 1892 xfermode == SkXfermode::kModulate_Mode); 1893 1894 if (xfermode == SkXfermode::kSrcIn_Mode || 1895 xfermode == SkXfermode::kSrcOut_Mode || 1896 xfermode == SkXfermode::kSrcATop_Mode) { 1897 drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), dst, 1898 &fExistingClipStack, fExistingClipRegion, 1899 SkXfermode::kSrcOver_Mode, 1900 xfermode == SkXfermode::kSrcOut_Mode); 1901 } else { 1902 SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode; 1903 if (xfermode == SkXfermode::kModulate_Mode) { 1904 drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), 1905 dst, &fExistingClipStack, 1906 fExistingClipRegion, 1907 SkXfermode::kSrcOver_Mode, false); 1908 mode = SkXfermode::kMultiply_Mode; 1909 } 1910 drawFormXObjectWithMask(addXObjectResource(dst), srcFormXObject.get(), 1911 &fExistingClipStack, fExistingClipRegion, mode, 1912 xfermode == SkXfermode::kDstOut_Mode); 1913 } 1914 } 1915 1916 bool SkPDFDevice::isContentEmpty() { 1917 ContentEntry* contentEntries = getContentEntries()->get(); 1918 if (!contentEntries || contentEntries->fContent.getOffset() == 0) { 1919 SkASSERT(!contentEntries || !contentEntries->fNext.get()); 1920 return true; 1921 } 1922 return false; 1923 } 1924 1925 void SkPDFDevice::populateGraphicStateEntryFromPaint( 1926 const SkMatrix& matrix, 1927 const SkClipStack& clipStack, 1928 const SkRegion& clipRegion, 1929 const SkPaint& paint, 1930 bool hasText, 1931 GraphicStateEntry* entry) { 1932 NOT_IMPLEMENTED(paint.getPathEffect() != NULL, false); 1933 NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false); 1934 NOT_IMPLEMENTED(paint.getColorFilter() != NULL, false); 1935 1936 entry->fMatrix = matrix; 1937 entry->fClipStack = clipStack; 1938 entry->fClipRegion = clipRegion; 1939 entry->fColor = SkColorSetA(paint.getColor(), 0xFF); 1940 entry->fShaderIndex = -1; 1941 1942 // PDF treats a shader as a color, so we only set one or the other. 1943 SkAutoTUnref<SkPDFObject> pdfShader; 1944 const SkShader* shader = paint.getShader(); 1945 SkColor color = paint.getColor(); 1946 if (shader) { 1947 // PDF positions patterns relative to the initial transform, so 1948 // we need to apply the current transform to the shader parameters. 1949 SkMatrix transform = matrix; 1950 transform.postConcat(fInitialTransform); 1951 1952 // PDF doesn't support kClamp_TileMode, so we simulate it by making 1953 // a pattern the size of the current clip. 1954 SkIRect bounds = clipRegion.getBounds(); 1955 1956 // We need to apply the initial transform to bounds in order to get 1957 // bounds in a consistent coordinate system. 1958 SkRect boundsTemp; 1959 boundsTemp.set(bounds); 1960 fInitialTransform.mapRect(&boundsTemp); 1961 boundsTemp.roundOut(&bounds); 1962 1963 pdfShader.reset(SkPDFShader::GetPDFShader(*shader, transform, bounds)); 1964 1965 if (pdfShader.get()) { 1966 // pdfShader has been canonicalized so we can directly compare 1967 // pointers. 1968 int resourceIndex = fShaderResources.find(pdfShader.get()); 1969 if (resourceIndex < 0) { 1970 resourceIndex = fShaderResources.count(); 1971 fShaderResources.push(pdfShader.get()); 1972 pdfShader.get()->ref(); 1973 } 1974 entry->fShaderIndex = resourceIndex; 1975 } else { 1976 // A color shader is treated as an invalid shader so we don't have 1977 // to set a shader just for a color. 1978 SkShader::GradientInfo gradientInfo; 1979 SkColor gradientColor; 1980 gradientInfo.fColors = &gradientColor; 1981 gradientInfo.fColorOffsets = NULL; 1982 gradientInfo.fColorCount = 1; 1983 if (shader->asAGradient(&gradientInfo) == 1984 SkShader::kColor_GradientType) { 1985 entry->fColor = SkColorSetA(gradientColor, 0xFF); 1986 color = gradientColor; 1987 } 1988 } 1989 } 1990 1991 SkAutoTUnref<SkPDFGraphicState> newGraphicState; 1992 if (color == paint.getColor()) { 1993 newGraphicState.reset( 1994 SkPDFGraphicState::GetGraphicStateForPaint(paint)); 1995 } else { 1996 SkPaint newPaint = paint; 1997 newPaint.setColor(color); 1998 newGraphicState.reset( 1999 SkPDFGraphicState::GetGraphicStateForPaint(newPaint)); 2000 } 2001 int resourceIndex = addGraphicStateResource(newGraphicState.get()); 2002 entry->fGraphicStateIndex = resourceIndex; 2003 2004 if (hasText) { 2005 entry->fTextScaleX = paint.getTextScaleX(); 2006 entry->fTextFill = paint.getStyle(); 2007 } else { 2008 entry->fTextScaleX = 0; 2009 } 2010 } 2011 2012 int SkPDFDevice::addGraphicStateResource(SkPDFGraphicState* gs) { 2013 // Assumes that gs has been canonicalized (so we can directly compare 2014 // pointers). 2015 int result = fGraphicStateResources.find(gs); 2016 if (result < 0) { 2017 result = fGraphicStateResources.count(); 2018 fGraphicStateResources.push(gs); 2019 gs->ref(); 2020 } 2021 return result; 2022 } 2023 2024 int SkPDFDevice::addXObjectResource(SkPDFObject* xObject) { 2025 // Assumes that xobject has been canonicalized (so we can directly compare 2026 // pointers). 2027 int result = fXObjectResources.find(xObject); 2028 if (result < 0) { 2029 result = fXObjectResources.count(); 2030 fXObjectResources.push(xObject); 2031 xObject->ref(); 2032 } 2033 return result; 2034 } 2035 2036 void SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID, 2037 ContentEntry* contentEntry) { 2038 SkTypeface* typeface = paint.getTypeface(); 2039 if (contentEntry->fState.fFont == NULL || 2040 contentEntry->fState.fTextSize != paint.getTextSize() || 2041 !contentEntry->fState.fFont->hasGlyph(glyphID)) { 2042 int fontIndex = getFontResourceIndex(typeface, glyphID); 2043 contentEntry->fContent.writeText("/"); 2044 contentEntry->fContent.writeText(SkPDFResourceDict::getResourceName( 2045 SkPDFResourceDict::kFont_ResourceType, 2046 fontIndex).c_str()); 2047 contentEntry->fContent.writeText(" "); 2048 SkPDFScalar::Append(paint.getTextSize(), &contentEntry->fContent); 2049 contentEntry->fContent.writeText(" Tf\n"); 2050 contentEntry->fState.fFont = fFontResources[fontIndex]; 2051 } 2052 } 2053 2054 int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) { 2055 SkAutoTUnref<SkPDFFont> newFont(SkPDFFont::GetFontResource(typeface, 2056 glyphID)); 2057 int resourceIndex = fFontResources.find(newFont.get()); 2058 if (resourceIndex < 0) { 2059 resourceIndex = fFontResources.count(); 2060 fFontResources.push(newFont.get()); 2061 newFont.get()->ref(); 2062 } 2063 return resourceIndex; 2064 } 2065 2066 void SkPDFDevice::internalDrawBitmap(const SkMatrix& origMatrix, 2067 const SkClipStack* clipStack, 2068 const SkRegion& origClipRegion, 2069 const SkBitmap& origBitmap, 2070 const SkIRect* srcRect, 2071 const SkPaint& paint) { 2072 SkMatrix matrix = origMatrix; 2073 SkRegion perspectiveBounds; 2074 const SkRegion* clipRegion = &origClipRegion; 2075 SkBitmap perspectiveBitmap; 2076 const SkBitmap* bitmap = &origBitmap; 2077 SkBitmap tmpSubsetBitmap; 2078 2079 // Rasterize the bitmap using perspective in a new bitmap. 2080 if (origMatrix.hasPerspective()) { 2081 if (fRasterDpi == 0) { 2082 return; 2083 } 2084 SkBitmap* subsetBitmap; 2085 if (srcRect) { 2086 if (!origBitmap.extractSubset(&tmpSubsetBitmap, *srcRect)) { 2087 return; 2088 } 2089 subsetBitmap = &tmpSubsetBitmap; 2090 } else { 2091 subsetBitmap = &tmpSubsetBitmap; 2092 *subsetBitmap = origBitmap; 2093 } 2094 srcRect = NULL; 2095 2096 // Transform the bitmap in the new space, without taking into 2097 // account the initial transform. 2098 SkPath perspectiveOutline; 2099 perspectiveOutline.addRect( 2100 SkRect::MakeWH(SkIntToScalar(subsetBitmap->width()), 2101 SkIntToScalar(subsetBitmap->height()))); 2102 perspectiveOutline.transform(origMatrix); 2103 2104 // TODO(edisonn): perf - use current clip too. 2105 // Retrieve the bounds of the new shape. 2106 SkRect bounds = perspectiveOutline.getBounds(); 2107 2108 // Transform the bitmap in the new space, taking into 2109 // account the initial transform. 2110 SkMatrix total = origMatrix; 2111 total.postConcat(fInitialTransform); 2112 total.postScale(SkIntToScalar(fRasterDpi) / 2113 SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE), 2114 SkIntToScalar(fRasterDpi) / 2115 SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE)); 2116 SkPath physicalPerspectiveOutline; 2117 physicalPerspectiveOutline.addRect( 2118 SkRect::MakeWH(SkIntToScalar(subsetBitmap->width()), 2119 SkIntToScalar(subsetBitmap->height()))); 2120 physicalPerspectiveOutline.transform(total); 2121 2122 SkScalar scaleX = physicalPerspectiveOutline.getBounds().width() / 2123 bounds.width(); 2124 SkScalar scaleY = physicalPerspectiveOutline.getBounds().height() / 2125 bounds.height(); 2126 2127 // TODO(edisonn): A better approach would be to use a bitmap shader 2128 // (in clamp mode) and draw a rect over the entire bounding box. Then 2129 // intersect perspectiveOutline to the clip. That will avoid introducing 2130 // alpha to the image while still giving good behavior at the edge of 2131 // the image. Avoiding alpha will reduce the pdf size and generation 2132 // CPU time some. 2133 2134 const int w = SkScalarCeilToInt(physicalPerspectiveOutline.getBounds().width()); 2135 const int h = SkScalarCeilToInt(physicalPerspectiveOutline.getBounds().height()); 2136 if (!perspectiveBitmap.tryAllocN32Pixels(w, h)) { 2137 return; 2138 } 2139 perspectiveBitmap.eraseColor(SK_ColorTRANSPARENT); 2140 2141 SkCanvas canvas(perspectiveBitmap); 2142 2143 SkScalar deltaX = bounds.left(); 2144 SkScalar deltaY = bounds.top(); 2145 2146 SkMatrix offsetMatrix = origMatrix; 2147 offsetMatrix.postTranslate(-deltaX, -deltaY); 2148 offsetMatrix.postScale(scaleX, scaleY); 2149 2150 // Translate the draw in the new canvas, so we perfectly fit the 2151 // shape in the bitmap. 2152 canvas.setMatrix(offsetMatrix); 2153 2154 canvas.drawBitmap(*subsetBitmap, SkIntToScalar(0), SkIntToScalar(0)); 2155 2156 // Make sure the final bits are in the bitmap. 2157 canvas.flush(); 2158 2159 // In the new space, we use the identity matrix translated 2160 // and scaled to reflect DPI. 2161 matrix.setScale(1 / scaleX, 1 / scaleY); 2162 matrix.postTranslate(deltaX, deltaY); 2163 2164 perspectiveBounds.setRect( 2165 SkIRect::MakeXYWH(SkScalarFloorToInt(bounds.x()), 2166 SkScalarFloorToInt(bounds.y()), 2167 SkScalarCeilToInt(bounds.width()), 2168 SkScalarCeilToInt(bounds.height()))); 2169 clipRegion = &perspectiveBounds; 2170 srcRect = NULL; 2171 bitmap = &perspectiveBitmap; 2172 } 2173 2174 SkMatrix scaled; 2175 // Adjust for origin flip. 2176 scaled.setScale(SK_Scalar1, -SK_Scalar1); 2177 scaled.postTranslate(0, SK_Scalar1); 2178 // Scale the image up from 1x1 to WxH. 2179 SkIRect subset = SkIRect::MakeWH(bitmap->width(), bitmap->height()); 2180 scaled.postScale(SkIntToScalar(subset.width()), 2181 SkIntToScalar(subset.height())); 2182 scaled.postConcat(matrix); 2183 ScopedContentEntry content(this, clipStack, *clipRegion, scaled, paint); 2184 if (!content.entry() || (srcRect && !subset.intersect(*srcRect))) { 2185 return; 2186 } 2187 if (content.needShape()) { 2188 SkPath shape; 2189 shape.addRect(SkRect::MakeWH(SkIntToScalar(subset.width()), 2190 SkIntToScalar( subset.height()))); 2191 shape.transform(matrix); 2192 content.setShape(shape); 2193 } 2194 if (!content.needSource()) { 2195 return; 2196 } 2197 2198 SkAutoTUnref<SkPDFObject> image( 2199 SkPDFCreateImageObject(*bitmap, subset, fEncoder)); 2200 if (!image) { 2201 return; 2202 } 2203 2204 SkPDFUtils::DrawFormXObject(this->addXObjectResource(image.get()), 2205 &content.entry()->fContent); 2206 } 2207 2208