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