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 (handlePointAnnotation(points, count, *d.fMatrix, passedPaint)) { | 806 if (SkAnnotation* annotation = passedPaint.getAnnotation()) { |
807 return; | 807 if (handlePointAnnotation(points, count, *d.fMatrix, annotation)) { |
| 808 return; |
| 809 } |
808 } | 810 } |
809 | 811 |
810 // SkDraw::drawPoints converts to multiple calls to fDevice->drawPath. | 812 // SkDraw::drawPoints converts to multiple calls to fDevice->drawPath. |
811 // We only use this when there's a path effect because of the overhead | 813 // We only use this when there's a path effect because of the overhead |
812 // of multiple calls to setUpContentEntry it causes. | 814 // of multiple calls to setUpContentEntry it causes. |
813 if (passedPaint.getPathEffect()) { | 815 if (passedPaint.getPathEffect()) { |
814 if (d.fClip->isEmpty()) { | 816 if (d.fClip->isEmpty()) { |
815 return; | 817 return; |
816 } | 818 } |
817 SkDraw pointDraw(d); | 819 SkDraw pointDraw(d); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
876 &content.entry()->fContent); | 878 &content.entry()->fContent); |
877 SkPDFUtils::ClosePath(&content.entry()->fContent); | 879 SkPDFUtils::ClosePath(&content.entry()->fContent); |
878 SkPDFUtils::StrokePath(&content.entry()->fContent); | 880 SkPDFUtils::StrokePath(&content.entry()->fContent); |
879 } | 881 } |
880 break; | 882 break; |
881 default: | 883 default: |
882 SkASSERT(false); | 884 SkASSERT(false); |
883 } | 885 } |
884 } | 886 } |
885 | 887 |
| 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 |
886 void SkPDFDevice::drawRect(const SkDraw& d, | 960 void SkPDFDevice::drawRect(const SkDraw& d, |
887 const SkRect& rect, | 961 const SkRect& rect, |
888 const SkPaint& srcPaint) { | 962 const SkPaint& srcPaint) { |
889 SkPaint paint = srcPaint; | 963 SkPaint paint = srcPaint; |
890 replace_srcmode_on_opaque_paint(&paint); | 964 replace_srcmode_on_opaque_paint(&paint); |
891 SkRect r = rect; | 965 SkRect r = rect; |
892 r.sort(); | 966 r.sort(); |
893 | 967 |
894 if (paint.getPathEffect()) { | 968 if (paint.getPathEffect()) { |
895 if (d.fClip->isEmpty()) { | 969 if (d.fClip->isEmpty()) { |
896 return; | 970 return; |
897 } | 971 } |
898 SkPath path; | 972 SkPath path; |
899 path.addRect(r); | 973 path.addRect(r); |
900 drawPath(d, path, paint, NULL, true); | 974 drawPath(d, path, paint, NULL, true); |
901 return; | 975 return; |
902 } | 976 } |
903 | 977 |
904 if (handleRectAnnotation(r, *d.fMatrix, paint)) { | 978 if (SkAnnotation* annotation = paint.getAnnotation()) { |
905 return; | 979 SkPath path; |
| 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 } |
906 } | 989 } |
907 | 990 |
908 ScopedContentEntry content(this, d, paint); | 991 ScopedContentEntry content(this, d, paint); |
909 if (!content.entry()) { | 992 if (!content.entry()) { |
910 return; | 993 return; |
911 } | 994 } |
912 SkPDFUtils::AppendRectangle(r, &content.entry()->fContent); | 995 SkPDFUtils::AppendRectangle(r, &content.entry()->fContent); |
913 SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType, | 996 SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType, |
914 &content.entry()->fContent); | 997 &content.entry()->fContent); |
915 } | 998 } |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
976 noEffectPaint.setStrokeWidth(0); | 1059 noEffectPaint.setStrokeWidth(0); |
977 } | 1060 } |
978 drawPath(d, *pathPtr, noEffectPaint, NULL, true); | 1061 drawPath(d, *pathPtr, noEffectPaint, NULL, true); |
979 return; | 1062 return; |
980 } | 1063 } |
981 | 1064 |
982 if (handleInversePath(d, origPath, paint, pathIsMutable, prePathMatrix)) { | 1065 if (handleInversePath(d, origPath, paint, pathIsMutable, prePathMatrix)) { |
983 return; | 1066 return; |
984 } | 1067 } |
985 | 1068 |
986 if (handleRectAnnotation(pathPtr->getBounds(), matrix, paint)) { | 1069 if (SkAnnotation* annotation = paint.getAnnotation()) { |
987 return; | 1070 SkRect transformedRect = |
| 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 } |
988 } | 1079 } |
989 | 1080 |
990 ScopedContentEntry content(this, d.fClipStack, *d.fClip, matrix, paint); | 1081 ScopedContentEntry content(this, d.fClipStack, *d.fClip, matrix, paint); |
991 if (!content.entry()) { | 1082 if (!content.entry()) { |
992 return; | 1083 return; |
993 } | 1084 } |
994 SkPDFUtils::EmitPath(*pathPtr, paint.getStyle(), | 1085 SkPDFUtils::EmitPath(*pathPtr, paint.getStyle(), |
995 &content.entry()->fContent); | 1086 &content.entry()->fContent); |
996 SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(), | 1087 SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(), |
997 &content.entry()->fContent); | 1088 &content.entry()->fContent); |
(...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1468 paint.getStrokeWidth() + SK_Scalar1); | 1559 paint.getStrokeWidth() + SK_Scalar1); |
1469 | 1560 |
1470 if (!calculate_inverse_path(bounds, *pathPtr, &modifiedPath)) { | 1561 if (!calculate_inverse_path(bounds, *pathPtr, &modifiedPath)) { |
1471 return false; | 1562 return false; |
1472 } | 1563 } |
1473 | 1564 |
1474 drawPath(d, modifiedPath, noInversePaint, prePathMatrix, true); | 1565 drawPath(d, modifiedPath, noInversePaint, prePathMatrix, true); |
1475 return true; | 1566 return true; |
1476 } | 1567 } |
1477 | 1568 |
1478 bool SkPDFDevice::handleRectAnnotation(const SkRect& r, const SkMatrix& matrix, | 1569 struct NamedDestination { |
1479 const SkPaint& p) { | 1570 SkAutoTUnref<const SkData> nameData; |
1480 SkAnnotation* annotationInfo = p.getAnnotation(); | 1571 SkPoint point; |
1481 if (!annotationInfo) { | 1572 |
1482 return false; | 1573 NamedDestination(const SkData* nameData, const SkPoint& point) |
1483 } | 1574 : nameData(SkRef(nameData)), point(point) {} |
1484 SkData* urlData = annotationInfo->find(SkAnnotationKeys::URL_Key()); | 1575 }; |
1485 if (urlData) { | 1576 |
1486 handleLinkToURL(urlData, r, matrix); | 1577 bool SkPDFDevice::handlePointAnnotation(const SkPoint* points, size_t count, |
1487 return p.getAnnotation() != NULL; | 1578 const SkMatrix& matrix, |
1488 } | 1579 SkAnnotation* annotationInfo) { |
1489 SkData* linkToName = annotationInfo->find( | 1580 SkData* nameData = annotationInfo->find( |
1490 SkAnnotationKeys::Link_Named_Dest_Key()); | 1581 SkAnnotationKeys::Define_Named_Dest_Key()); |
1491 if (linkToName) { | 1582 if (nameData) { |
1492 handleLinkToNamedDest(linkToName, r, matrix); | 1583 SkMatrix transform = matrix; |
1493 return p.getAnnotation() != NULL; | 1584 transform.postConcat(fInitialTransform); |
| 1585 for (size_t i = 0; i < count; i++) { |
| 1586 SkPoint translatedPoint; |
| 1587 transform.mapXY(points[i].x(), points[i].y(), &translatedPoint); |
| 1588 fNamedDestinations.push( |
| 1589 SkNEW_ARGS(NamedDestination, (nameData, translatedPoint))); |
| 1590 |
| 1591 } |
| 1592 return true; |
1494 } | 1593 } |
1495 return false; | 1594 return false; |
1496 } | 1595 } |
1497 | |
1498 bool SkPDFDevice::handlePointAnnotation(const SkPoint* points, size_t count, | |
1499 const SkMatrix& matrix, | |
1500 const SkPaint& paint) { | |
1501 SkAnnotation* annotationInfo = paint.getAnnotation(); | |
1502 if (!annotationInfo) { | |
1503 return false; | |
1504 } | |
1505 SkData* nameData = annotationInfo->find( | |
1506 SkAnnotationKeys::Define_Named_Dest_Key()); | |
1507 if (nameData) { | |
1508 for (size_t i = 0; i < count; i++) { | |
1509 defineNamedDestination(nameData, points[i], matrix); | |
1510 } | |
1511 return paint.getAnnotation() != NULL; | |
1512 } | |
1513 return false; | |
1514 } | |
1515 | 1596 |
1516 void SkPDFDevice::addAnnotation(SkPDFDict* annotation) { | 1597 void SkPDFDevice::addAnnotation(SkPDFDict* annotation) { |
1517 if (NULL == fAnnotations) { | 1598 if (NULL == fAnnotations) { |
1518 fAnnotations = SkNEW(SkPDFArray); | 1599 fAnnotations = SkNEW(SkPDFArray); |
1519 } | 1600 } |
1520 fAnnotations->appendObject(annotation); | 1601 fAnnotations->appendObject(annotation); |
1521 } | 1602 } |
1522 | 1603 |
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 } | |
1597 | 1604 |
1598 void SkPDFDevice::appendDestinations(SkPDFDict* dict, SkPDFObject* page) const { | 1605 void SkPDFDevice::appendDestinations(SkPDFDict* dict, SkPDFObject* page) const { |
1599 int nDest = fNamedDestinations.count(); | 1606 int nDest = fNamedDestinations.count(); |
1600 for (int i = 0; i < nDest; i++) { | 1607 for (int i = 0; i < nDest; i++) { |
1601 NamedDestination* dest = fNamedDestinations[i]; | 1608 NamedDestination* dest = fNamedDestinations[i]; |
1602 SkAutoTUnref<SkPDFArray> pdfDest(SkNEW(SkPDFArray)); | 1609 SkAutoTUnref<SkPDFArray> pdfDest(SkNEW(SkPDFArray)); |
1603 pdfDest->reserve(5); | 1610 pdfDest->reserve(5); |
1604 pdfDest->appendObjRef(SkRef(page)); | 1611 pdfDest->appendObjRef(SkRef(page)); |
1605 pdfDest->appendName("XYZ"); | 1612 pdfDest->appendName("XYZ"); |
1606 pdfDest->appendScalar(dest->point.x()); | 1613 pdfDest->appendScalar(dest->point.x()); |
(...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2194 return; | 2201 return; |
2195 } | 2202 } |
2196 SkAutoTUnref<SkPDFObject> image(SkPDFBitmap::Create(fCanon, subsetBitmap)); | 2203 SkAutoTUnref<SkPDFObject> image(SkPDFBitmap::Create(fCanon, subsetBitmap)); |
2197 if (!image) { | 2204 if (!image) { |
2198 return; | 2205 return; |
2199 } | 2206 } |
2200 | 2207 |
2201 SkPDFUtils::DrawFormXObject(this->addXObjectResource(image.get()), | 2208 SkPDFUtils::DrawFormXObject(this->addXObjectResource(image.get()), |
2202 &content.entry()->fContent); | 2209 &content.entry()->fContent); |
2203 } | 2210 } |
OLD | NEW |