| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkPDFDevice.h" | 8 #include "SkPDFDevice.h" |
| 9 | 9 |
| 10 #include "SkAnnotation.h" | 10 #include "SkAnnotation.h" |
| (...skipping 786 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 797 size_t count, | 797 size_t count, |
| 798 const SkPoint* points, | 798 const SkPoint* points, |
| 799 const SkPaint& srcPaint) { | 799 const SkPaint& srcPaint) { |
| 800 SkPaint passedPaint = srcPaint; | 800 SkPaint passedPaint = srcPaint; |
| 801 replace_srcmode_on_opaque_paint(&passedPaint); | 801 replace_srcmode_on_opaque_paint(&passedPaint); |
| 802 | 802 |
| 803 if (count == 0) { | 803 if (count == 0) { |
| 804 return; | 804 return; |
| 805 } | 805 } |
| 806 | 806 |
| 807 if (handlePointAnnotation(points, count, *d.fMatrix, passedPaint)) { | 807 if (SkAnnotation* annotation = passedPaint.getAnnotation()) { |
| 808 return; | 808 if (handlePointAnnotation(points, count, *d.fMatrix, annotation)) { |
| 809 return; |
| 810 } |
| 809 } | 811 } |
| 810 | 812 |
| 811 // SkDraw::drawPoints converts to multiple calls to fDevice->drawPath. | 813 // SkDraw::drawPoints converts to multiple calls to fDevice->drawPath. |
| 812 // We only use this when there's a path effect because of the overhead | 814 // We only use this when there's a path effect because of the overhead |
| 813 // of multiple calls to setUpContentEntry it causes. | 815 // of multiple calls to setUpContentEntry it causes. |
| 814 if (passedPaint.getPathEffect()) { | 816 if (passedPaint.getPathEffect()) { |
| 815 if (d.fClip->isEmpty()) { | 817 if (d.fClip->isEmpty()) { |
| 816 return; | 818 return; |
| 817 } | 819 } |
| 818 SkDraw pointDraw(d); | 820 SkDraw pointDraw(d); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 877 &content.entry()->fContent); | 879 &content.entry()->fContent); |
| 878 SkPDFUtils::ClosePath(&content.entry()->fContent); | 880 SkPDFUtils::ClosePath(&content.entry()->fContent); |
| 879 SkPDFUtils::StrokePath(&content.entry()->fContent); | 881 SkPDFUtils::StrokePath(&content.entry()->fContent); |
| 880 } | 882 } |
| 881 break; | 883 break; |
| 882 default: | 884 default: |
| 883 SkASSERT(false); | 885 SkASSERT(false); |
| 884 } | 886 } |
| 885 } | 887 } |
| 886 | 888 |
| 889 static SkPath transform_and_clip_path(const SkDraw& d, |
| 890 const SkPath& region, |
| 891 const SkMatrix& initialTransform) { |
| 892 SkPath path = region; |
| 893 SkMatrix transform = *d.fMatrix; |
| 894 transform.postConcat(initialTransform); |
| 895 path.transform(transform); |
| 896 if (const SkClipStack* clipStack = d.fClipStack) { |
| 897 SkPath clip; |
| 898 (void)clipStack->asPath(&clip); |
| 899 clip.transform(initialTransform); |
| 900 Op(clip, path, SkPathOp::kIntersect_SkPathOp, &path); |
| 901 } |
| 902 return path; |
| 903 } |
| 904 |
| 905 static SkPDFDict* create_link_annotation(const SkRect& translatedRect) { |
| 906 SkAutoTUnref<SkPDFDict> annotation(SkNEW_ARGS(SkPDFDict, ("Annot"))); |
| 907 annotation->insertName("Subtype", "Link"); |
| 908 |
| 909 SkAutoTUnref<SkPDFArray> border(SkNEW(SkPDFArray)); |
| 910 border->reserve(3); |
| 911 border->appendInt(0); // Horizontal corner radius. |
| 912 border->appendInt(0); // Vertical corner radius. |
| 913 border->appendInt(0); // Width, 0 = no border. |
| 914 annotation->insertObject("Border", border.detach()); |
| 915 |
| 916 SkAutoTUnref<SkPDFArray> rect(SkNEW(SkPDFArray)); |
| 917 rect->reserve(4); |
| 918 rect->appendScalar(translatedRect.fLeft); |
| 919 rect->appendScalar(translatedRect.fTop); |
| 920 rect->appendScalar(translatedRect.fRight); |
| 921 rect->appendScalar(translatedRect.fBottom); |
| 922 annotation->insertObject("Rect", rect.detach()); |
| 923 |
| 924 return annotation.detach(); |
| 925 } |
| 926 |
| 927 static SkPDFDict* create_link_to_url(SkData* urlData, const SkRect& r) { |
| 928 SkAutoTUnref<SkPDFDict> annotation(create_link_annotation(r)); |
| 929 |
| 930 SkString url(static_cast<const char *>(urlData->data()), |
| 931 urlData->size() - 1); |
| 932 SkAutoTUnref<SkPDFDict> action(SkNEW_ARGS(SkPDFDict, ("Action"))); |
| 933 action->insertName("S", "URI"); |
| 934 action->insertString("URI", url); |
| 935 annotation->insertObject("A", action.detach()); |
| 936 return annotation.detach(); |
| 937 } |
| 938 |
| 939 static SkPDFDict* create_link_named_dest(SkData* nameData, const SkRect& r) { |
| 940 SkAutoTUnref<SkPDFDict> annotation(create_link_annotation(r)); |
| 941 SkString name(static_cast<const char *>(nameData->data()), |
| 942 nameData->size() - 1); |
| 943 annotation->insertName("Dest", name); |
| 944 return annotation.detach(); |
| 945 } |
| 946 |
| 947 static SkPDFDict* create_rect_annotation(const SkRect& r, |
| 948 SkAnnotation* annotation) { |
| 949 SkASSERT(annotation); |
| 950 SkData* urlData = annotation->find(SkAnnotationKeys::URL_Key()); |
| 951 if (urlData) { |
| 952 return create_link_to_url(urlData, r); |
| 953 } |
| 954 SkData* linkToName = |
| 955 annotation->find(SkAnnotationKeys::Link_Named_Dest_Key()); |
| 956 if (linkToName) { |
| 957 return create_link_named_dest(linkToName, r); |
| 958 } |
| 959 return NULL; |
| 960 } |
| 961 |
| 887 void SkPDFDevice::drawRect(const SkDraw& d, | 962 void SkPDFDevice::drawRect(const SkDraw& d, |
| 888 const SkRect& rect, | 963 const SkRect& rect, |
| 889 const SkPaint& srcPaint) { | 964 const SkPaint& srcPaint) { |
| 890 SkPaint paint = srcPaint; | 965 SkPaint paint = srcPaint; |
| 891 replace_srcmode_on_opaque_paint(&paint); | 966 replace_srcmode_on_opaque_paint(&paint); |
| 892 SkRect r = rect; | 967 SkRect r = rect; |
| 893 r.sort(); | 968 r.sort(); |
| 894 | 969 |
| 895 if (paint.getPathEffect()) { | 970 if (paint.getPathEffect()) { |
| 896 if (d.fClip->isEmpty()) { | 971 if (d.fClip->isEmpty()) { |
| 897 return; | 972 return; |
| 898 } | 973 } |
| 899 SkPath path; | 974 SkPath path; |
| 900 path.addRect(r); | 975 path.addRect(r); |
| 901 drawPath(d, path, paint, NULL, true); | 976 drawPath(d, path, paint, NULL, true); |
| 902 return; | 977 return; |
| 903 } | 978 } |
| 904 | 979 |
| 905 if (handleRectAnnotation(r, *d.fMatrix, paint)) { | 980 if (SkAnnotation* annotation = paint.getAnnotation()) { |
| 906 return; | 981 SkPath path; |
| 982 path.addRect(rect); |
| 983 SkRect transformedRect = |
| 984 transform_and_clip_path(d, path, fInitialTransform).getBounds(); |
| 985 SkAutoTUnref<SkPDFDict> annot( |
| 986 create_rect_annotation(transformedRect, annotation)); |
| 987 if (annot) { |
| 988 this->addAnnotation(annot.detach()); |
| 989 return; |
| 990 } |
| 907 } | 991 } |
| 908 | 992 |
| 909 ScopedContentEntry content(this, d, paint); | 993 ScopedContentEntry content(this, d, paint); |
| 910 if (!content.entry()) { | 994 if (!content.entry()) { |
| 911 return; | 995 return; |
| 912 } | 996 } |
| 913 SkPDFUtils::AppendRectangle(r, &content.entry()->fContent); | 997 SkPDFUtils::AppendRectangle(r, &content.entry()->fContent); |
| 914 SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType, | 998 SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType, |
| 915 &content.entry()->fContent); | 999 &content.entry()->fContent); |
| 916 } | 1000 } |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 977 noEffectPaint.setStrokeWidth(0); | 1061 noEffectPaint.setStrokeWidth(0); |
| 978 } | 1062 } |
| 979 drawPath(d, *pathPtr, noEffectPaint, NULL, true); | 1063 drawPath(d, *pathPtr, noEffectPaint, NULL, true); |
| 980 return; | 1064 return; |
| 981 } | 1065 } |
| 982 | 1066 |
| 983 if (handleInversePath(d, origPath, paint, pathIsMutable, prePathMatrix)) { | 1067 if (handleInversePath(d, origPath, paint, pathIsMutable, prePathMatrix)) { |
| 984 return; | 1068 return; |
| 985 } | 1069 } |
| 986 | 1070 |
| 987 if (handleRectAnnotation(pathPtr->getBounds(), matrix, paint)) { | 1071 if (SkAnnotation* annotation = paint.getAnnotation()) { |
| 988 return; | 1072 SkRect transformedRect = |
| 1073 transform_and_clip_path(d, *pathPtr, fInitialTransform) |
| 1074 .getBounds(); |
| 1075 SkAutoTUnref<SkPDFDict> annot( |
| 1076 create_rect_annotation(transformedRect, annotation)); |
| 1077 if (annot) { |
| 1078 this->addAnnotation(annot.detach()); |
| 1079 return; |
| 1080 } |
| 989 } | 1081 } |
| 990 | 1082 |
| 991 ScopedContentEntry content(this, d.fClipStack, *d.fClip, matrix, paint); | 1083 ScopedContentEntry content(this, d.fClipStack, *d.fClip, matrix, paint); |
| 992 if (!content.entry()) { | 1084 if (!content.entry()) { |
| 993 return; | 1085 return; |
| 994 } | 1086 } |
| 995 SkPDFUtils::EmitPath(*pathPtr, paint.getStyle(), | 1087 SkPDFUtils::EmitPath(*pathPtr, paint.getStyle(), |
| 996 &content.entry()->fContent); | 1088 &content.entry()->fContent); |
| 997 SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(), | 1089 SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(), |
| 998 &content.entry()->fContent); | 1090 &content.entry()->fContent); |
| (...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1469 paint.getStrokeWidth() + SK_Scalar1); | 1561 paint.getStrokeWidth() + SK_Scalar1); |
| 1470 | 1562 |
| 1471 if (!calculate_inverse_path(bounds, *pathPtr, &modifiedPath)) { | 1563 if (!calculate_inverse_path(bounds, *pathPtr, &modifiedPath)) { |
| 1472 return false; | 1564 return false; |
| 1473 } | 1565 } |
| 1474 | 1566 |
| 1475 drawPath(d, modifiedPath, noInversePaint, prePathMatrix, true); | 1567 drawPath(d, modifiedPath, noInversePaint, prePathMatrix, true); |
| 1476 return true; | 1568 return true; |
| 1477 } | 1569 } |
| 1478 | 1570 |
| 1479 bool SkPDFDevice::handleRectAnnotation(const SkRect& r, const SkMatrix& matrix, | 1571 struct NamedDestination { |
| 1480 const SkPaint& p) { | 1572 SkAutoTUnref<const SkData> nameData; |
| 1481 SkAnnotation* annotationInfo = p.getAnnotation(); | 1573 SkPoint point; |
| 1482 if (!annotationInfo) { | 1574 |
| 1483 return false; | 1575 NamedDestination(const SkData* nameData, const SkPoint& point) |
| 1484 } | 1576 : nameData(SkRef(nameData)), point(point) {} |
| 1485 SkData* urlData = annotationInfo->find(SkAnnotationKeys::URL_Key()); | 1577 }; |
| 1486 if (urlData) { | 1578 |
| 1487 handleLinkToURL(urlData, r, matrix); | 1579 bool SkPDFDevice::handlePointAnnotation(const SkPoint* points, size_t count, |
| 1488 return p.getAnnotation() != NULL; | 1580 const SkMatrix& matrix, |
| 1489 } | 1581 SkAnnotation* annotationInfo) { |
| 1490 SkData* linkToName = annotationInfo->find( | 1582 SkData* nameData = annotationInfo->find( |
| 1491 SkAnnotationKeys::Link_Named_Dest_Key()); | 1583 SkAnnotationKeys::Define_Named_Dest_Key()); |
| 1492 if (linkToName) { | 1584 if (nameData) { |
| 1493 handleLinkToNamedDest(linkToName, r, matrix); | 1585 SkMatrix transform = matrix; |
| 1494 return p.getAnnotation() != NULL; | 1586 transform.postConcat(fInitialTransform); |
| 1587 for (size_t i = 0; i < count; i++) { |
| 1588 SkPoint translatedPoint; |
| 1589 transform.mapXY(points[i].x(), points[i].y(), &translatedPoint); |
| 1590 fNamedDestinations.push( |
| 1591 SkNEW_ARGS(NamedDestination, (nameData, translatedPoint))); |
| 1592 |
| 1593 } |
| 1594 return true; |
| 1495 } | 1595 } |
| 1496 return false; | 1596 return false; |
| 1497 } | 1597 } |
| 1498 | |
| 1499 bool SkPDFDevice::handlePointAnnotation(const SkPoint* points, size_t count, | |
| 1500 const SkMatrix& matrix, | |
| 1501 const SkPaint& paint) { | |
| 1502 SkAnnotation* annotationInfo = paint.getAnnotation(); | |
| 1503 if (!annotationInfo) { | |
| 1504 return false; | |
| 1505 } | |
| 1506 SkData* nameData = annotationInfo->find( | |
| 1507 SkAnnotationKeys::Define_Named_Dest_Key()); | |
| 1508 if (nameData) { | |
| 1509 for (size_t i = 0; i < count; i++) { | |
| 1510 defineNamedDestination(nameData, points[i], matrix); | |
| 1511 } | |
| 1512 return paint.getAnnotation() != NULL; | |
| 1513 } | |
| 1514 return false; | |
| 1515 } | |
| 1516 | 1598 |
| 1517 void SkPDFDevice::addAnnotation(SkPDFDict* annotation) { | 1599 void SkPDFDevice::addAnnotation(SkPDFDict* annotation) { |
| 1518 if (NULL == fAnnotations) { | 1600 if (NULL == fAnnotations) { |
| 1519 fAnnotations = SkNEW(SkPDFArray); | 1601 fAnnotations = SkNEW(SkPDFArray); |
| 1520 } | 1602 } |
| 1521 fAnnotations->appendObject(annotation); | 1603 fAnnotations->appendObject(annotation); |
| 1522 } | 1604 } |
| 1523 | 1605 |
| 1524 static SkPDFDict* create_link_annotation(const SkRect& r, | |
| 1525 const SkMatrix& initialTransform, | |
| 1526 const SkMatrix& matrix) { | |
| 1527 SkMatrix transform = matrix; | |
| 1528 transform.postConcat(initialTransform); | |
| 1529 SkRect translatedRect; | |
| 1530 transform.mapRect(&translatedRect, r); | |
| 1531 | |
| 1532 SkAutoTUnref<SkPDFDict> annotation(SkNEW_ARGS(SkPDFDict, ("Annot"))); | |
| 1533 annotation->insertName("Subtype", "Link"); | |
| 1534 | |
| 1535 SkAutoTUnref<SkPDFArray> border(SkNEW(SkPDFArray)); | |
| 1536 border->reserve(3); | |
| 1537 border->appendInt(0); // Horizontal corner radius. | |
| 1538 border->appendInt(0); // Vertical corner radius. | |
| 1539 border->appendInt(0); // Width, 0 = no border. | |
| 1540 annotation->insertObject("Border", border.detach()); | |
| 1541 | |
| 1542 SkAutoTUnref<SkPDFArray> rect(SkNEW(SkPDFArray)); | |
| 1543 rect->reserve(4); | |
| 1544 rect->appendScalar(translatedRect.fLeft); | |
| 1545 rect->appendScalar(translatedRect.fTop); | |
| 1546 rect->appendScalar(translatedRect.fRight); | |
| 1547 rect->appendScalar(translatedRect.fBottom); | |
| 1548 annotation->insertObject("Rect", rect.detach()); | |
| 1549 | |
| 1550 return annotation.detach(); | |
| 1551 } | |
| 1552 | |
| 1553 void SkPDFDevice::handleLinkToURL(SkData* urlData, const SkRect& r, | |
| 1554 const SkMatrix& matrix) { | |
| 1555 SkAutoTUnref<SkPDFDict> annotation( | |
| 1556 create_link_annotation(r, fInitialTransform, matrix)); | |
| 1557 | |
| 1558 SkString url(static_cast<const char *>(urlData->data()), | |
| 1559 urlData->size() - 1); | |
| 1560 SkAutoTUnref<SkPDFDict> action(SkNEW_ARGS(SkPDFDict, ("Action"))); | |
| 1561 action->insertName("S", "URI"); | |
| 1562 action->insertString("URI", url); | |
| 1563 annotation->insertObject("A", action.detach()); | |
| 1564 this->addAnnotation(annotation.detach()); | |
| 1565 } | |
| 1566 | |
| 1567 void SkPDFDevice::handleLinkToNamedDest(SkData* nameData, const SkRect& r, | |
| 1568 const SkMatrix& matrix) { | |
| 1569 SkAutoTUnref<SkPDFDict> annotation( | |
| 1570 create_link_annotation(r, fInitialTransform, matrix)); | |
| 1571 SkString name(static_cast<const char *>(nameData->data()), | |
| 1572 nameData->size() - 1); | |
| 1573 annotation->insertName("Dest", name); | |
| 1574 this->addAnnotation(annotation.detach()); | |
| 1575 } | |
| 1576 | |
| 1577 struct NamedDestination { | |
| 1578 const SkData* nameData; | |
| 1579 SkPoint point; | |
| 1580 | |
| 1581 NamedDestination(const SkData* nameData, const SkPoint& point) | |
| 1582 : nameData(SkRef(nameData)), point(point) {} | |
| 1583 | |
| 1584 ~NamedDestination() { | |
| 1585 nameData->unref(); | |
| 1586 } | |
| 1587 }; | |
| 1588 | |
| 1589 void SkPDFDevice::defineNamedDestination(SkData* nameData, const SkPoint& point, | |
| 1590 const SkMatrix& matrix) { | |
| 1591 SkMatrix transform = matrix; | |
| 1592 transform.postConcat(fInitialTransform); | |
| 1593 SkPoint translatedPoint; | |
| 1594 transform.mapXY(point.x(), point.y(), &translatedPoint); | |
| 1595 fNamedDestinations.push( | |
| 1596 SkNEW_ARGS(NamedDestination, (nameData, translatedPoint))); | |
| 1597 } | |
| 1598 | 1606 |
| 1599 void SkPDFDevice::appendDestinations(SkPDFDict* dict, SkPDFObject* page) const { | 1607 void SkPDFDevice::appendDestinations(SkPDFDict* dict, SkPDFObject* page) const { |
| 1600 int nDest = fNamedDestinations.count(); | 1608 int nDest = fNamedDestinations.count(); |
| 1601 for (int i = 0; i < nDest; i++) { | 1609 for (int i = 0; i < nDest; i++) { |
| 1602 NamedDestination* dest = fNamedDestinations[i]; | 1610 NamedDestination* dest = fNamedDestinations[i]; |
| 1603 SkAutoTUnref<SkPDFArray> pdfDest(SkNEW(SkPDFArray)); | 1611 SkAutoTUnref<SkPDFArray> pdfDest(SkNEW(SkPDFArray)); |
| 1604 pdfDest->reserve(5); | 1612 pdfDest->reserve(5); |
| 1605 pdfDest->appendObjRef(SkRef(page)); | 1613 pdfDest->appendObjRef(SkRef(page)); |
| 1606 pdfDest->appendName("XYZ"); | 1614 pdfDest->appendName("XYZ"); |
| 1607 pdfDest->appendScalar(dest->point.x()); | 1615 pdfDest->appendScalar(dest->point.x()); |
| (...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2195 return; | 2203 return; |
| 2196 } | 2204 } |
| 2197 SkAutoTUnref<SkPDFObject> image(SkPDFBitmap::Create(fCanon, subsetBitmap)); | 2205 SkAutoTUnref<SkPDFObject> image(SkPDFBitmap::Create(fCanon, subsetBitmap)); |
| 2198 if (!image) { | 2206 if (!image) { |
| 2199 return; | 2207 return; |
| 2200 } | 2208 } |
| 2201 | 2209 |
| 2202 SkPDFUtils::DrawFormXObject(this->addXObjectResource(image.get()), | 2210 SkPDFUtils::DrawFormXObject(this->addXObjectResource(image.get()), |
| 2203 &content.entry()->fContent); | 2211 &content.entry()->fContent); |
| 2204 } | 2212 } |
| OLD | NEW |