author | simon <simon> | 2002-11-08 15:20:59 (UTC) |
---|---|---|
committer | simon <simon> | 2002-11-08 15:20:59 (UTC) |
commit | d8ac5b68b504536136347547816992b1cf605cd4 (patch) (unidiff) | |
tree | 7e90b9c23b78c7c67b5433bebd6a29e3e98e4bac | |
parent | 447735be20fad2642617e3ba4f7ef0b598f597db (diff) | |
download | opie-d8ac5b68b504536136347547816992b1cf605cd4.zip opie-d8ac5b68b504536136347547816992b1cf605cd4.tar.gz opie-d8ac5b68b504536136347547816992b1cf605cd4.tar.bz2 |
- a couple of fixes like this one:
- fprintf(f, "%g", real);
+ fprintf(f, "%g", static_cast<double>(real));
with 'real' being a fouble object. as fprintf is a c function with variable
arguments one cannot pass non-primitive objects through it and there is
no way for the compiler to figure out the right conversion operator, so
we give it a helping hand :)
-rw-r--r-- | noncore/unsupported/qpdf/xpdf/Gfx.cc | 2 | ||||
-rw-r--r-- | noncore/unsupported/qpdf/xpdf/Object.cc | 2 | ||||
-rw-r--r-- | noncore/unsupported/qpdf/xpdf/Page.cc | 4 |
3 files changed, 4 insertions, 4 deletions
diff --git a/noncore/unsupported/qpdf/xpdf/Gfx.cc b/noncore/unsupported/qpdf/xpdf/Gfx.cc index 17d613e..f016c0e 100644 --- a/noncore/unsupported/qpdf/xpdf/Gfx.cc +++ b/noncore/unsupported/qpdf/xpdf/Gfx.cc | |||
@@ -843,1918 +843,1918 @@ void Gfx::opSetFillColorSpace(Object args[], int numArgs) { | |||
843 | } | 843 | } |
844 | for (i = 0; i < gfxColorMaxComps; ++i) { | 844 | for (i = 0; i < gfxColorMaxComps; ++i) { |
845 | color.c[i] = 0; | 845 | color.c[i] = 0; |
846 | } | 846 | } |
847 | state->setFillColor(&color); | 847 | state->setFillColor(&color); |
848 | out->updateFillColor(state); | 848 | out->updateFillColor(state); |
849 | } | 849 | } |
850 | 850 | ||
851 | void Gfx::opSetStrokeColorSpace(Object args[], int numArgs) { | 851 | void Gfx::opSetStrokeColorSpace(Object args[], int numArgs) { |
852 | Object obj; | 852 | Object obj; |
853 | GfxColorSpace *colorSpace; | 853 | GfxColorSpace *colorSpace; |
854 | GfxColor color; | 854 | GfxColor color; |
855 | int i; | 855 | int i; |
856 | 856 | ||
857 | state->setStrokePattern(NULL); | 857 | state->setStrokePattern(NULL); |
858 | res->lookupColorSpace(args[0].getName(), &obj); | 858 | res->lookupColorSpace(args[0].getName(), &obj); |
859 | if (obj.isNull()) { | 859 | if (obj.isNull()) { |
860 | colorSpace = GfxColorSpace::parse(&args[0]); | 860 | colorSpace = GfxColorSpace::parse(&args[0]); |
861 | } else { | 861 | } else { |
862 | colorSpace = GfxColorSpace::parse(&obj); | 862 | colorSpace = GfxColorSpace::parse(&obj); |
863 | } | 863 | } |
864 | obj.free(); | 864 | obj.free(); |
865 | if (colorSpace) { | 865 | if (colorSpace) { |
866 | state->setStrokeColorSpace(colorSpace); | 866 | state->setStrokeColorSpace(colorSpace); |
867 | } else { | 867 | } else { |
868 | error(getPos(), "Bad color space (stroke)"); | 868 | error(getPos(), "Bad color space (stroke)"); |
869 | } | 869 | } |
870 | for (i = 0; i < gfxColorMaxComps; ++i) { | 870 | for (i = 0; i < gfxColorMaxComps; ++i) { |
871 | color.c[i] = 0; | 871 | color.c[i] = 0; |
872 | } | 872 | } |
873 | state->setStrokeColor(&color); | 873 | state->setStrokeColor(&color); |
874 | out->updateStrokeColor(state); | 874 | out->updateStrokeColor(state); |
875 | } | 875 | } |
876 | 876 | ||
877 | void Gfx::opSetFillColor(Object args[], int numArgs) { | 877 | void Gfx::opSetFillColor(Object args[], int numArgs) { |
878 | GfxColor color; | 878 | GfxColor color; |
879 | int i; | 879 | int i; |
880 | 880 | ||
881 | state->setFillPattern(NULL); | 881 | state->setFillPattern(NULL); |
882 | for (i = 0; i < numArgs; ++i) { | 882 | for (i = 0; i < numArgs; ++i) { |
883 | color.c[i] = args[i].getNum(); | 883 | color.c[i] = args[i].getNum(); |
884 | } | 884 | } |
885 | state->setFillColor(&color); | 885 | state->setFillColor(&color); |
886 | out->updateFillColor(state); | 886 | out->updateFillColor(state); |
887 | } | 887 | } |
888 | 888 | ||
889 | void Gfx::opSetStrokeColor(Object args[], int numArgs) { | 889 | void Gfx::opSetStrokeColor(Object args[], int numArgs) { |
890 | GfxColor color; | 890 | GfxColor color; |
891 | int i; | 891 | int i; |
892 | 892 | ||
893 | state->setStrokePattern(NULL); | 893 | state->setStrokePattern(NULL); |
894 | for (i = 0; i < numArgs; ++i) { | 894 | for (i = 0; i < numArgs; ++i) { |
895 | color.c[i] = args[i].getNum(); | 895 | color.c[i] = args[i].getNum(); |
896 | } | 896 | } |
897 | state->setStrokeColor(&color); | 897 | state->setStrokeColor(&color); |
898 | out->updateStrokeColor(state); | 898 | out->updateStrokeColor(state); |
899 | } | 899 | } |
900 | 900 | ||
901 | void Gfx::opSetFillColorN(Object args[], int numArgs) { | 901 | void Gfx::opSetFillColorN(Object args[], int numArgs) { |
902 | GfxColor color; | 902 | GfxColor color; |
903 | GfxPattern *pattern; | 903 | GfxPattern *pattern; |
904 | int i; | 904 | int i; |
905 | 905 | ||
906 | if (state->getFillColorSpace()->getMode() == csPattern) { | 906 | if (state->getFillColorSpace()->getMode() == csPattern) { |
907 | if (numArgs > 1) { | 907 | if (numArgs > 1) { |
908 | for (i = 0; i < numArgs && i < 4; ++i) { | 908 | for (i = 0; i < numArgs && i < 4; ++i) { |
909 | if (args[i].isNum()) { | 909 | if (args[i].isNum()) { |
910 | color.c[i] = args[i].getNum(); | 910 | color.c[i] = args[i].getNum(); |
911 | } | 911 | } |
912 | } | 912 | } |
913 | state->setFillColor(&color); | 913 | state->setFillColor(&color); |
914 | out->updateFillColor(state); | 914 | out->updateFillColor(state); |
915 | } | 915 | } |
916 | if (args[numArgs-1].isName() && | 916 | if (args[numArgs-1].isName() && |
917 | (pattern = res->lookupPattern(args[numArgs-1].getName()))) { | 917 | (pattern = res->lookupPattern(args[numArgs-1].getName()))) { |
918 | state->setFillPattern(pattern); | 918 | state->setFillPattern(pattern); |
919 | } | 919 | } |
920 | 920 | ||
921 | } else { | 921 | } else { |
922 | state->setFillPattern(NULL); | 922 | state->setFillPattern(NULL); |
923 | for (i = 0; i < numArgs && i < 4; ++i) { | 923 | for (i = 0; i < numArgs && i < 4; ++i) { |
924 | if (args[i].isNum()) { | 924 | if (args[i].isNum()) { |
925 | color.c[i] = args[i].getNum(); | 925 | color.c[i] = args[i].getNum(); |
926 | } | 926 | } |
927 | } | 927 | } |
928 | state->setFillColor(&color); | 928 | state->setFillColor(&color); |
929 | out->updateFillColor(state); | 929 | out->updateFillColor(state); |
930 | } | 930 | } |
931 | } | 931 | } |
932 | 932 | ||
933 | void Gfx::opSetStrokeColorN(Object args[], int numArgs) { | 933 | void Gfx::opSetStrokeColorN(Object args[], int numArgs) { |
934 | GfxColor color; | 934 | GfxColor color; |
935 | GfxPattern *pattern; | 935 | GfxPattern *pattern; |
936 | int i; | 936 | int i; |
937 | 937 | ||
938 | if (state->getStrokeColorSpace()->getMode() == csPattern) { | 938 | if (state->getStrokeColorSpace()->getMode() == csPattern) { |
939 | if (numArgs > 1) { | 939 | if (numArgs > 1) { |
940 | for (i = 0; i < numArgs && i < 4; ++i) { | 940 | for (i = 0; i < numArgs && i < 4; ++i) { |
941 | if (args[i].isNum()) { | 941 | if (args[i].isNum()) { |
942 | color.c[i] = args[i].getNum(); | 942 | color.c[i] = args[i].getNum(); |
943 | } | 943 | } |
944 | } | 944 | } |
945 | state->setStrokeColor(&color); | 945 | state->setStrokeColor(&color); |
946 | out->updateStrokeColor(state); | 946 | out->updateStrokeColor(state); |
947 | } | 947 | } |
948 | if (args[numArgs-1].isName() && | 948 | if (args[numArgs-1].isName() && |
949 | (pattern = res->lookupPattern(args[numArgs-1].getName()))) { | 949 | (pattern = res->lookupPattern(args[numArgs-1].getName()))) { |
950 | state->setStrokePattern(pattern); | 950 | state->setStrokePattern(pattern); |
951 | } | 951 | } |
952 | 952 | ||
953 | } else { | 953 | } else { |
954 | state->setStrokePattern(NULL); | 954 | state->setStrokePattern(NULL); |
955 | for (i = 0; i < numArgs && i < 4; ++i) { | 955 | for (i = 0; i < numArgs && i < 4; ++i) { |
956 | if (args[i].isNum()) { | 956 | if (args[i].isNum()) { |
957 | color.c[i] = args[i].getNum(); | 957 | color.c[i] = args[i].getNum(); |
958 | } | 958 | } |
959 | } | 959 | } |
960 | state->setStrokeColor(&color); | 960 | state->setStrokeColor(&color); |
961 | out->updateStrokeColor(state); | 961 | out->updateStrokeColor(state); |
962 | } | 962 | } |
963 | } | 963 | } |
964 | 964 | ||
965 | //------------------------------------------------------------------------ | 965 | //------------------------------------------------------------------------ |
966 | // path segment operators | 966 | // path segment operators |
967 | //------------------------------------------------------------------------ | 967 | //------------------------------------------------------------------------ |
968 | 968 | ||
969 | void Gfx::opMoveTo(Object args[], int numArgs) { | 969 | void Gfx::opMoveTo(Object args[], int numArgs) { |
970 | state->moveTo(args[0].getNum(), args[1].getNum()); | 970 | state->moveTo(args[0].getNum(), args[1].getNum()); |
971 | } | 971 | } |
972 | 972 | ||
973 | void Gfx::opLineTo(Object args[], int numArgs) { | 973 | void Gfx::opLineTo(Object args[], int numArgs) { |
974 | if (!state->isCurPt()) { | 974 | if (!state->isCurPt()) { |
975 | error(getPos(), "No current point in lineto"); | 975 | error(getPos(), "No current point in lineto"); |
976 | return; | 976 | return; |
977 | } | 977 | } |
978 | state->lineTo(args[0].getNum(), args[1].getNum()); | 978 | state->lineTo(args[0].getNum(), args[1].getNum()); |
979 | } | 979 | } |
980 | 980 | ||
981 | void Gfx::opCurveTo(Object args[], int numArgs) { | 981 | void Gfx::opCurveTo(Object args[], int numArgs) { |
982 | fouble x1, y1, x2, y2, x3, y3; | 982 | fouble x1, y1, x2, y2, x3, y3; |
983 | 983 | ||
984 | if (!state->isCurPt()) { | 984 | if (!state->isCurPt()) { |
985 | error(getPos(), "No current point in curveto"); | 985 | error(getPos(), "No current point in curveto"); |
986 | return; | 986 | return; |
987 | } | 987 | } |
988 | x1 = args[0].getNum(); | 988 | x1 = args[0].getNum(); |
989 | y1 = args[1].getNum(); | 989 | y1 = args[1].getNum(); |
990 | x2 = args[2].getNum(); | 990 | x2 = args[2].getNum(); |
991 | y2 = args[3].getNum(); | 991 | y2 = args[3].getNum(); |
992 | x3 = args[4].getNum(); | 992 | x3 = args[4].getNum(); |
993 | y3 = args[5].getNum(); | 993 | y3 = args[5].getNum(); |
994 | state->curveTo(x1, y1, x2, y2, x3, y3); | 994 | state->curveTo(x1, y1, x2, y2, x3, y3); |
995 | } | 995 | } |
996 | 996 | ||
997 | void Gfx::opCurveTo1(Object args[], int numArgs) { | 997 | void Gfx::opCurveTo1(Object args[], int numArgs) { |
998 | fouble x1, y1, x2, y2, x3, y3; | 998 | fouble x1, y1, x2, y2, x3, y3; |
999 | 999 | ||
1000 | if (!state->isCurPt()) { | 1000 | if (!state->isCurPt()) { |
1001 | error(getPos(), "No current point in curveto1"); | 1001 | error(getPos(), "No current point in curveto1"); |
1002 | return; | 1002 | return; |
1003 | } | 1003 | } |
1004 | x1 = state->getCurX(); | 1004 | x1 = state->getCurX(); |
1005 | y1 = state->getCurY(); | 1005 | y1 = state->getCurY(); |
1006 | x2 = args[0].getNum(); | 1006 | x2 = args[0].getNum(); |
1007 | y2 = args[1].getNum(); | 1007 | y2 = args[1].getNum(); |
1008 | x3 = args[2].getNum(); | 1008 | x3 = args[2].getNum(); |
1009 | y3 = args[3].getNum(); | 1009 | y3 = args[3].getNum(); |
1010 | state->curveTo(x1, y1, x2, y2, x3, y3); | 1010 | state->curveTo(x1, y1, x2, y2, x3, y3); |
1011 | } | 1011 | } |
1012 | 1012 | ||
1013 | void Gfx::opCurveTo2(Object args[], int numArgs) { | 1013 | void Gfx::opCurveTo2(Object args[], int numArgs) { |
1014 | fouble x1, y1, x2, y2, x3, y3; | 1014 | fouble x1, y1, x2, y2, x3, y3; |
1015 | 1015 | ||
1016 | if (!state->isCurPt()) { | 1016 | if (!state->isCurPt()) { |
1017 | error(getPos(), "No current point in curveto2"); | 1017 | error(getPos(), "No current point in curveto2"); |
1018 | return; | 1018 | return; |
1019 | } | 1019 | } |
1020 | x1 = args[0].getNum(); | 1020 | x1 = args[0].getNum(); |
1021 | y1 = args[1].getNum(); | 1021 | y1 = args[1].getNum(); |
1022 | x2 = args[2].getNum(); | 1022 | x2 = args[2].getNum(); |
1023 | y2 = args[3].getNum(); | 1023 | y2 = args[3].getNum(); |
1024 | x3 = x2; | 1024 | x3 = x2; |
1025 | y3 = y2; | 1025 | y3 = y2; |
1026 | state->curveTo(x1, y1, x2, y2, x3, y3); | 1026 | state->curveTo(x1, y1, x2, y2, x3, y3); |
1027 | } | 1027 | } |
1028 | 1028 | ||
1029 | void Gfx::opRectangle(Object args[], int numArgs) { | 1029 | void Gfx::opRectangle(Object args[], int numArgs) { |
1030 | fouble x, y, w, h; | 1030 | fouble x, y, w, h; |
1031 | 1031 | ||
1032 | x = args[0].getNum(); | 1032 | x = args[0].getNum(); |
1033 | y = args[1].getNum(); | 1033 | y = args[1].getNum(); |
1034 | w = args[2].getNum(); | 1034 | w = args[2].getNum(); |
1035 | h = args[3].getNum(); | 1035 | h = args[3].getNum(); |
1036 | state->moveTo(x, y); | 1036 | state->moveTo(x, y); |
1037 | state->lineTo(x + w, y); | 1037 | state->lineTo(x + w, y); |
1038 | state->lineTo(x + w, y + h); | 1038 | state->lineTo(x + w, y + h); |
1039 | state->lineTo(x, y + h); | 1039 | state->lineTo(x, y + h); |
1040 | state->closePath(); | 1040 | state->closePath(); |
1041 | } | 1041 | } |
1042 | 1042 | ||
1043 | void Gfx::opClosePath(Object args[], int numArgs) { | 1043 | void Gfx::opClosePath(Object args[], int numArgs) { |
1044 | if (!state->isCurPt()) { | 1044 | if (!state->isCurPt()) { |
1045 | error(getPos(), "No current point in closepath"); | 1045 | error(getPos(), "No current point in closepath"); |
1046 | return; | 1046 | return; |
1047 | } | 1047 | } |
1048 | state->closePath(); | 1048 | state->closePath(); |
1049 | } | 1049 | } |
1050 | 1050 | ||
1051 | //------------------------------------------------------------------------ | 1051 | //------------------------------------------------------------------------ |
1052 | // path painting operators | 1052 | // path painting operators |
1053 | //------------------------------------------------------------------------ | 1053 | //------------------------------------------------------------------------ |
1054 | 1054 | ||
1055 | void Gfx::opEndPath(Object args[], int numArgs) { | 1055 | void Gfx::opEndPath(Object args[], int numArgs) { |
1056 | doEndPath(); | 1056 | doEndPath(); |
1057 | } | 1057 | } |
1058 | 1058 | ||
1059 | void Gfx::opStroke(Object args[], int numArgs) { | 1059 | void Gfx::opStroke(Object args[], int numArgs) { |
1060 | if (!state->isCurPt()) { | 1060 | if (!state->isCurPt()) { |
1061 | //error(getPos(), "No path in stroke"); | 1061 | //error(getPos(), "No path in stroke"); |
1062 | return; | 1062 | return; |
1063 | } | 1063 | } |
1064 | if (state->isPath()) | 1064 | if (state->isPath()) |
1065 | out->stroke(state); | 1065 | out->stroke(state); |
1066 | doEndPath(); | 1066 | doEndPath(); |
1067 | } | 1067 | } |
1068 | 1068 | ||
1069 | void Gfx::opCloseStroke(Object args[], int numArgs) { | 1069 | void Gfx::opCloseStroke(Object args[], int numArgs) { |
1070 | if (!state->isCurPt()) { | 1070 | if (!state->isCurPt()) { |
1071 | //error(getPos(), "No path in closepath/stroke"); | 1071 | //error(getPos(), "No path in closepath/stroke"); |
1072 | return; | 1072 | return; |
1073 | } | 1073 | } |
1074 | if (state->isPath()) { | 1074 | if (state->isPath()) { |
1075 | state->closePath(); | 1075 | state->closePath(); |
1076 | out->stroke(state); | 1076 | out->stroke(state); |
1077 | } | 1077 | } |
1078 | doEndPath(); | 1078 | doEndPath(); |
1079 | } | 1079 | } |
1080 | 1080 | ||
1081 | void Gfx::opFill(Object args[], int numArgs) { | 1081 | void Gfx::opFill(Object args[], int numArgs) { |
1082 | if (!state->isCurPt()) { | 1082 | if (!state->isCurPt()) { |
1083 | //error(getPos(), "No path in fill"); | 1083 | //error(getPos(), "No path in fill"); |
1084 | return; | 1084 | return; |
1085 | } | 1085 | } |
1086 | if (state->isPath()) { | 1086 | if (state->isPath()) { |
1087 | if (state->getFillColorSpace()->getMode() == csPattern) { | 1087 | if (state->getFillColorSpace()->getMode() == csPattern) { |
1088 | doPatternFill(gFalse); | 1088 | doPatternFill(gFalse); |
1089 | } else { | 1089 | } else { |
1090 | out->fill(state); | 1090 | out->fill(state); |
1091 | } | 1091 | } |
1092 | } | 1092 | } |
1093 | doEndPath(); | 1093 | doEndPath(); |
1094 | } | 1094 | } |
1095 | 1095 | ||
1096 | void Gfx::opEOFill(Object args[], int numArgs) { | 1096 | void Gfx::opEOFill(Object args[], int numArgs) { |
1097 | if (!state->isCurPt()) { | 1097 | if (!state->isCurPt()) { |
1098 | //error(getPos(), "No path in eofill"); | 1098 | //error(getPos(), "No path in eofill"); |
1099 | return; | 1099 | return; |
1100 | } | 1100 | } |
1101 | if (state->isPath()) { | 1101 | if (state->isPath()) { |
1102 | if (state->getFillColorSpace()->getMode() == csPattern) { | 1102 | if (state->getFillColorSpace()->getMode() == csPattern) { |
1103 | doPatternFill(gTrue); | 1103 | doPatternFill(gTrue); |
1104 | } else { | 1104 | } else { |
1105 | out->eoFill(state); | 1105 | out->eoFill(state); |
1106 | } | 1106 | } |
1107 | } | 1107 | } |
1108 | doEndPath(); | 1108 | doEndPath(); |
1109 | } | 1109 | } |
1110 | 1110 | ||
1111 | void Gfx::opFillStroke(Object args[], int numArgs) { | 1111 | void Gfx::opFillStroke(Object args[], int numArgs) { |
1112 | if (!state->isCurPt()) { | 1112 | if (!state->isCurPt()) { |
1113 | //error(getPos(), "No path in fill/stroke"); | 1113 | //error(getPos(), "No path in fill/stroke"); |
1114 | return; | 1114 | return; |
1115 | } | 1115 | } |
1116 | if (state->isPath()) { | 1116 | if (state->isPath()) { |
1117 | if (state->getFillColorSpace()->getMode() == csPattern) { | 1117 | if (state->getFillColorSpace()->getMode() == csPattern) { |
1118 | doPatternFill(gFalse); | 1118 | doPatternFill(gFalse); |
1119 | } else { | 1119 | } else { |
1120 | out->fill(state); | 1120 | out->fill(state); |
1121 | } | 1121 | } |
1122 | out->stroke(state); | 1122 | out->stroke(state); |
1123 | } | 1123 | } |
1124 | doEndPath(); | 1124 | doEndPath(); |
1125 | } | 1125 | } |
1126 | 1126 | ||
1127 | void Gfx::opCloseFillStroke(Object args[], int numArgs) { | 1127 | void Gfx::opCloseFillStroke(Object args[], int numArgs) { |
1128 | if (!state->isCurPt()) { | 1128 | if (!state->isCurPt()) { |
1129 | //error(getPos(), "No path in closepath/fill/stroke"); | 1129 | //error(getPos(), "No path in closepath/fill/stroke"); |
1130 | return; | 1130 | return; |
1131 | } | 1131 | } |
1132 | if (state->isPath()) { | 1132 | if (state->isPath()) { |
1133 | state->closePath(); | 1133 | state->closePath(); |
1134 | if (state->getFillColorSpace()->getMode() == csPattern) { | 1134 | if (state->getFillColorSpace()->getMode() == csPattern) { |
1135 | doPatternFill(gFalse); | 1135 | doPatternFill(gFalse); |
1136 | } else { | 1136 | } else { |
1137 | out->fill(state); | 1137 | out->fill(state); |
1138 | } | 1138 | } |
1139 | out->stroke(state); | 1139 | out->stroke(state); |
1140 | } | 1140 | } |
1141 | doEndPath(); | 1141 | doEndPath(); |
1142 | } | 1142 | } |
1143 | 1143 | ||
1144 | void Gfx::opEOFillStroke(Object args[], int numArgs) { | 1144 | void Gfx::opEOFillStroke(Object args[], int numArgs) { |
1145 | if (!state->isCurPt()) { | 1145 | if (!state->isCurPt()) { |
1146 | //error(getPos(), "No path in eofill/stroke"); | 1146 | //error(getPos(), "No path in eofill/stroke"); |
1147 | return; | 1147 | return; |
1148 | } | 1148 | } |
1149 | if (state->isPath()) { | 1149 | if (state->isPath()) { |
1150 | if (state->getFillColorSpace()->getMode() == csPattern) { | 1150 | if (state->getFillColorSpace()->getMode() == csPattern) { |
1151 | doPatternFill(gTrue); | 1151 | doPatternFill(gTrue); |
1152 | } else { | 1152 | } else { |
1153 | out->eoFill(state); | 1153 | out->eoFill(state); |
1154 | } | 1154 | } |
1155 | out->stroke(state); | 1155 | out->stroke(state); |
1156 | } | 1156 | } |
1157 | doEndPath(); | 1157 | doEndPath(); |
1158 | } | 1158 | } |
1159 | 1159 | ||
1160 | void Gfx::opCloseEOFillStroke(Object args[], int numArgs) { | 1160 | void Gfx::opCloseEOFillStroke(Object args[], int numArgs) { |
1161 | if (!state->isCurPt()) { | 1161 | if (!state->isCurPt()) { |
1162 | //error(getPos(), "No path in closepath/eofill/stroke"); | 1162 | //error(getPos(), "No path in closepath/eofill/stroke"); |
1163 | return; | 1163 | return; |
1164 | } | 1164 | } |
1165 | if (state->isPath()) { | 1165 | if (state->isPath()) { |
1166 | state->closePath(); | 1166 | state->closePath(); |
1167 | if (state->getFillColorSpace()->getMode() == csPattern) { | 1167 | if (state->getFillColorSpace()->getMode() == csPattern) { |
1168 | doPatternFill(gTrue); | 1168 | doPatternFill(gTrue); |
1169 | } else { | 1169 | } else { |
1170 | out->eoFill(state); | 1170 | out->eoFill(state); |
1171 | } | 1171 | } |
1172 | out->stroke(state); | 1172 | out->stroke(state); |
1173 | } | 1173 | } |
1174 | doEndPath(); | 1174 | doEndPath(); |
1175 | } | 1175 | } |
1176 | 1176 | ||
1177 | void Gfx::doPatternFill(GBool eoFill) { | 1177 | void Gfx::doPatternFill(GBool eoFill) { |
1178 | GfxPatternColorSpace *patCS; | 1178 | GfxPatternColorSpace *patCS; |
1179 | GfxPattern *pattern; | 1179 | GfxPattern *pattern; |
1180 | GfxTilingPattern *tPat; | 1180 | GfxTilingPattern *tPat; |
1181 | GfxColorSpace *cs; | 1181 | GfxColorSpace *cs; |
1182 | fouble xMin, yMin, xMax, yMax, x, y, x1, y1; | 1182 | fouble xMin, yMin, xMax, yMax, x, y, x1, y1; |
1183 | fouble cxMin, cyMin, cxMax, cyMax; | 1183 | fouble cxMin, cyMin, cxMax, cyMax; |
1184 | int xi0, yi0, xi1, yi1, xi, yi; | 1184 | int xi0, yi0, xi1, yi1, xi, yi; |
1185 | fouble *ctm, *btm, *ptm; | 1185 | fouble *ctm, *btm, *ptm; |
1186 | fouble m[6], ictm[6], m1[6], imb[6]; | 1186 | fouble m[6], ictm[6], m1[6], imb[6]; |
1187 | fouble det; | 1187 | fouble det; |
1188 | fouble xstep, ystep; | 1188 | fouble xstep, ystep; |
1189 | int i; | 1189 | int i; |
1190 | 1190 | ||
1191 | // this is a bit of a kludge -- patterns can be really slow, so we | 1191 | // this is a bit of a kludge -- patterns can be really slow, so we |
1192 | // skip them if we're only doing text extraction, since they almost | 1192 | // skip them if we're only doing text extraction, since they almost |
1193 | // certainly don't contain any text | 1193 | // certainly don't contain any text |
1194 | if (!out->needNonText()) { | 1194 | if (!out->needNonText()) { |
1195 | return; | 1195 | return; |
1196 | } | 1196 | } |
1197 | 1197 | ||
1198 | // get color space | 1198 | // get color space |
1199 | patCS = (GfxPatternColorSpace *)state->getFillColorSpace(); | 1199 | patCS = (GfxPatternColorSpace *)state->getFillColorSpace(); |
1200 | 1200 | ||
1201 | // get pattern | 1201 | // get pattern |
1202 | if (!(pattern = state->getFillPattern())) { | 1202 | if (!(pattern = state->getFillPattern())) { |
1203 | return; | 1203 | return; |
1204 | } | 1204 | } |
1205 | if (pattern->getType() != 1) { | 1205 | if (pattern->getType() != 1) { |
1206 | return; | 1206 | return; |
1207 | } | 1207 | } |
1208 | tPat = (GfxTilingPattern *)pattern; | 1208 | tPat = (GfxTilingPattern *)pattern; |
1209 | 1209 | ||
1210 | // construct a (pattern space) -> (current space) transform matrix | 1210 | // construct a (pattern space) -> (current space) transform matrix |
1211 | ctm = state->getCTM(); | 1211 | ctm = state->getCTM(); |
1212 | btm = baseMatrix; | 1212 | btm = baseMatrix; |
1213 | ptm = tPat->getMatrix(); | 1213 | ptm = tPat->getMatrix(); |
1214 | // iCTM = invert CTM | 1214 | // iCTM = invert CTM |
1215 | det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]); | 1215 | det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]); |
1216 | ictm[0] = ctm[3] * det; | 1216 | ictm[0] = ctm[3] * det; |
1217 | ictm[1] = -ctm[1] * det; | 1217 | ictm[1] = -ctm[1] * det; |
1218 | ictm[2] = -ctm[2] * det; | 1218 | ictm[2] = -ctm[2] * det; |
1219 | ictm[3] = ctm[0] * det; | 1219 | ictm[3] = ctm[0] * det; |
1220 | ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det; | 1220 | ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det; |
1221 | ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det; | 1221 | ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det; |
1222 | // m1 = PTM * BTM = PTM * base transform matrix | 1222 | // m1 = PTM * BTM = PTM * base transform matrix |
1223 | m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2]; | 1223 | m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2]; |
1224 | m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3]; | 1224 | m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3]; |
1225 | m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2]; | 1225 | m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2]; |
1226 | m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3]; | 1226 | m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3]; |
1227 | m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4]; | 1227 | m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4]; |
1228 | m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5]; | 1228 | m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5]; |
1229 | // m = m1 * iCTM = (PTM * BTM) * (iCTM) | 1229 | // m = m1 * iCTM = (PTM * BTM) * (iCTM) |
1230 | m[0] = m1[0] * ictm[0] + m1[1] * ictm[2]; | 1230 | m[0] = m1[0] * ictm[0] + m1[1] * ictm[2]; |
1231 | m[1] = m1[0] * ictm[1] + m1[1] * ictm[3]; | 1231 | m[1] = m1[0] * ictm[1] + m1[1] * ictm[3]; |
1232 | m[2] = m1[2] * ictm[0] + m1[3] * ictm[2]; | 1232 | m[2] = m1[2] * ictm[0] + m1[3] * ictm[2]; |
1233 | m[3] = m1[2] * ictm[1] + m1[3] * ictm[3]; | 1233 | m[3] = m1[2] * ictm[1] + m1[3] * ictm[3]; |
1234 | m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4]; | 1234 | m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4]; |
1235 | m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5]; | 1235 | m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5]; |
1236 | 1236 | ||
1237 | // construct a (base space) -> (pattern space) transform matrix | 1237 | // construct a (base space) -> (pattern space) transform matrix |
1238 | det = 1 / (m1[0] * m1[3] - m1[1] * m1[2]); | 1238 | det = 1 / (m1[0] * m1[3] - m1[1] * m1[2]); |
1239 | imb[0] = m1[3] * det; | 1239 | imb[0] = m1[3] * det; |
1240 | imb[1] = -m1[1] * det; | 1240 | imb[1] = -m1[1] * det; |
1241 | imb[2] = -m1[2] * det; | 1241 | imb[2] = -m1[2] * det; |
1242 | imb[3] = m1[0] * det; | 1242 | imb[3] = m1[0] * det; |
1243 | imb[4] = (m1[2] * m1[5] - m1[3] * m1[4]) * det; | 1243 | imb[4] = (m1[2] * m1[5] - m1[3] * m1[4]) * det; |
1244 | imb[5] = (m1[1] * m1[4] - m1[0] * m1[5]) * det; | 1244 | imb[5] = (m1[1] * m1[4] - m1[0] * m1[5]) * det; |
1245 | 1245 | ||
1246 | // save current graphics state | 1246 | // save current graphics state |
1247 | out->saveState(state); | 1247 | out->saveState(state); |
1248 | state = state->save(); | 1248 | state = state->save(); |
1249 | 1249 | ||
1250 | // set underlying color space (for uncolored tiling patterns) | 1250 | // set underlying color space (for uncolored tiling patterns) |
1251 | if (tPat->getPaintType() == 2 && (cs = patCS->getUnder())) { | 1251 | if (tPat->getPaintType() == 2 && (cs = patCS->getUnder())) { |
1252 | state->setFillColorSpace(cs->copy()); | 1252 | state->setFillColorSpace(cs->copy()); |
1253 | } else { | 1253 | } else { |
1254 | state->setFillColorSpace(new GfxDeviceGrayColorSpace()); | 1254 | state->setFillColorSpace(new GfxDeviceGrayColorSpace()); |
1255 | } | 1255 | } |
1256 | state->setFillPattern(NULL); | 1256 | state->setFillPattern(NULL); |
1257 | out->updateFillColor(state); | 1257 | out->updateFillColor(state); |
1258 | 1258 | ||
1259 | // clip to current path | 1259 | // clip to current path |
1260 | state->clip(); | 1260 | state->clip(); |
1261 | if (eoFill) { | 1261 | if (eoFill) { |
1262 | out->eoClip(state); | 1262 | out->eoClip(state); |
1263 | } else { | 1263 | } else { |
1264 | out->clip(state); | 1264 | out->clip(state); |
1265 | } | 1265 | } |
1266 | state->clearPath(); | 1266 | state->clearPath(); |
1267 | 1267 | ||
1268 | // transform clip region bbox to pattern space | 1268 | // transform clip region bbox to pattern space |
1269 | state->getClipBBox(&cxMin, &cyMin, &cxMax, &cyMax); | 1269 | state->getClipBBox(&cxMin, &cyMin, &cxMax, &cyMax); |
1270 | xMin = xMax = cxMin * imb[0] + cyMin * imb[2] + imb[4]; | 1270 | xMin = xMax = cxMin * imb[0] + cyMin * imb[2] + imb[4]; |
1271 | yMin = yMax = cxMin * imb[1] + cyMin * imb[3] + imb[5]; | 1271 | yMin = yMax = cxMin * imb[1] + cyMin * imb[3] + imb[5]; |
1272 | x1 = cxMin * imb[0] + cyMax * imb[2] + imb[4]; | 1272 | x1 = cxMin * imb[0] + cyMax * imb[2] + imb[4]; |
1273 | y1 = cxMin * imb[1] + cyMax * imb[3] + imb[5]; | 1273 | y1 = cxMin * imb[1] + cyMax * imb[3] + imb[5]; |
1274 | if (x1 < xMin) { | 1274 | if (x1 < xMin) { |
1275 | xMin = x1; | 1275 | xMin = x1; |
1276 | } else if (x1 > xMax) { | 1276 | } else if (x1 > xMax) { |
1277 | xMax = x1; | 1277 | xMax = x1; |
1278 | } | 1278 | } |
1279 | if (y1 < yMin) { | 1279 | if (y1 < yMin) { |
1280 | yMin = y1; | 1280 | yMin = y1; |
1281 | } else if (y1 > yMax) { | 1281 | } else if (y1 > yMax) { |
1282 | yMax = y1; | 1282 | yMax = y1; |
1283 | } | 1283 | } |
1284 | x1 = cxMax * imb[0] + cyMin * imb[2] + imb[4]; | 1284 | x1 = cxMax * imb[0] + cyMin * imb[2] + imb[4]; |
1285 | y1 = cxMax * imb[1] + cyMin * imb[3] + imb[5]; | 1285 | y1 = cxMax * imb[1] + cyMin * imb[3] + imb[5]; |
1286 | if (x1 < xMin) { | 1286 | if (x1 < xMin) { |
1287 | xMin = x1; | 1287 | xMin = x1; |
1288 | } else if (x1 > xMax) { | 1288 | } else if (x1 > xMax) { |
1289 | xMax = x1; | 1289 | xMax = x1; |
1290 | } | 1290 | } |
1291 | if (y1 < yMin) { | 1291 | if (y1 < yMin) { |
1292 | yMin = y1; | 1292 | yMin = y1; |
1293 | } else if (y1 > yMax) { | 1293 | } else if (y1 > yMax) { |
1294 | yMax = y1; | 1294 | yMax = y1; |
1295 | } | 1295 | } |
1296 | x1 = cxMax * imb[0] + cyMax * imb[2] + imb[4]; | 1296 | x1 = cxMax * imb[0] + cyMax * imb[2] + imb[4]; |
1297 | y1 = cxMax * imb[1] + cyMax * imb[3] + imb[5]; | 1297 | y1 = cxMax * imb[1] + cyMax * imb[3] + imb[5]; |
1298 | if (x1 < xMin) { | 1298 | if (x1 < xMin) { |
1299 | xMin = x1; | 1299 | xMin = x1; |
1300 | } else if (x1 > xMax) { | 1300 | } else if (x1 > xMax) { |
1301 | xMax = x1; | 1301 | xMax = x1; |
1302 | } | 1302 | } |
1303 | if (y1 < yMin) { | 1303 | if (y1 < yMin) { |
1304 | yMin = y1; | 1304 | yMin = y1; |
1305 | } else if (y1 > yMax) { | 1305 | } else if (y1 > yMax) { |
1306 | yMax = y1; | 1306 | yMax = y1; |
1307 | } | 1307 | } |
1308 | 1308 | ||
1309 | // draw the pattern | 1309 | // draw the pattern |
1310 | //~ this should treat negative steps differently -- start at right/top | 1310 | //~ this should treat negative steps differently -- start at right/top |
1311 | //~ edge instead of left/bottom (?) | 1311 | //~ edge instead of left/bottom (?) |
1312 | xstep = fabs(tPat->getXStep()); | 1312 | xstep = fabs(tPat->getXStep()); |
1313 | ystep = fabs(tPat->getYStep()); | 1313 | ystep = fabs(tPat->getYStep()); |
1314 | xi0 = (int)floor(xMin / xstep); | 1314 | xi0 = (int)floor(xMin / xstep); |
1315 | xi1 = (int)ceil(xMax / xstep); | 1315 | xi1 = (int)ceil(xMax / xstep); |
1316 | yi0 = (int)floor(yMin / ystep); | 1316 | yi0 = (int)floor(yMin / ystep); |
1317 | yi1 = (int)ceil(yMax / ystep); | 1317 | yi1 = (int)ceil(yMax / ystep); |
1318 | for (i = 0; i < 4; ++i) { | 1318 | for (i = 0; i < 4; ++i) { |
1319 | m1[i] = m[i]; | 1319 | m1[i] = m[i]; |
1320 | } | 1320 | } |
1321 | for (yi = yi0; yi < yi1; ++yi) { | 1321 | for (yi = yi0; yi < yi1; ++yi) { |
1322 | for (xi = xi0; xi < xi1; ++xi) { | 1322 | for (xi = xi0; xi < xi1; ++xi) { |
1323 | x = xi * xstep; | 1323 | x = xi * xstep; |
1324 | y = yi * ystep; | 1324 | y = yi * ystep; |
1325 | m1[4] = x * m[0] + y * m[2] + m[4]; | 1325 | m1[4] = x * m[0] + y * m[2] + m[4]; |
1326 | m1[5] = x * m[1] + y * m[3] + m[5]; | 1326 | m1[5] = x * m[1] + y * m[3] + m[5]; |
1327 | doForm1(tPat->getContentStream(), tPat->getResDict(), | 1327 | doForm1(tPat->getContentStream(), tPat->getResDict(), |
1328 | m1, tPat->getBBox()); | 1328 | m1, tPat->getBBox()); |
1329 | } | 1329 | } |
1330 | } | 1330 | } |
1331 | 1331 | ||
1332 | // restore graphics state | 1332 | // restore graphics state |
1333 | state = state->restore(); | 1333 | state = state->restore(); |
1334 | out->restoreState(state); | 1334 | out->restoreState(state); |
1335 | } | 1335 | } |
1336 | 1336 | ||
1337 | void Gfx::opShFill(Object args[], int numArgs) { | 1337 | void Gfx::opShFill(Object args[], int numArgs) { |
1338 | GfxShading *shading; | 1338 | GfxShading *shading; |
1339 | fouble xMin, yMin, xMax, yMax; | 1339 | fouble xMin, yMin, xMax, yMax; |
1340 | 1340 | ||
1341 | if (!(shading = res->lookupShading(args[0].getName()))) { | 1341 | if (!(shading = res->lookupShading(args[0].getName()))) { |
1342 | return; | 1342 | return; |
1343 | } | 1343 | } |
1344 | 1344 | ||
1345 | // save current graphics state | 1345 | // save current graphics state |
1346 | out->saveState(state); | 1346 | out->saveState(state); |
1347 | state = state->save(); | 1347 | state = state->save(); |
1348 | 1348 | ||
1349 | // clip to bbox | 1349 | // clip to bbox |
1350 | if (shading->getHasBBox()) { | 1350 | if (shading->getHasBBox()) { |
1351 | shading->getBBox(&xMin, &yMin, &xMax, &yMax); | 1351 | shading->getBBox(&xMin, &yMin, &xMax, &yMax); |
1352 | state->moveTo(xMin, yMin); | 1352 | state->moveTo(xMin, yMin); |
1353 | state->lineTo(xMax, yMin); | 1353 | state->lineTo(xMax, yMin); |
1354 | state->lineTo(xMax, yMax); | 1354 | state->lineTo(xMax, yMax); |
1355 | state->lineTo(xMin, yMax); | 1355 | state->lineTo(xMin, yMax); |
1356 | state->closePath(); | 1356 | state->closePath(); |
1357 | state->clip(); | 1357 | state->clip(); |
1358 | out->clip(state); | 1358 | out->clip(state); |
1359 | state->clearPath(); | 1359 | state->clearPath(); |
1360 | } | 1360 | } |
1361 | 1361 | ||
1362 | // set the color space | 1362 | // set the color space |
1363 | state->setFillColorSpace(shading->getColorSpace()->copy()); | 1363 | state->setFillColorSpace(shading->getColorSpace()->copy()); |
1364 | 1364 | ||
1365 | // do shading type-specific operations | 1365 | // do shading type-specific operations |
1366 | switch (shading->getType()) { | 1366 | switch (shading->getType()) { |
1367 | case 2: | 1367 | case 2: |
1368 | doAxialShFill((GfxAxialShading *)shading); | 1368 | doAxialShFill((GfxAxialShading *)shading); |
1369 | break; | 1369 | break; |
1370 | case 3: | 1370 | case 3: |
1371 | doRadialShFill((GfxRadialShading *)shading); | 1371 | doRadialShFill((GfxRadialShading *)shading); |
1372 | break; | 1372 | break; |
1373 | } | 1373 | } |
1374 | 1374 | ||
1375 | // restore graphics state | 1375 | // restore graphics state |
1376 | state = state->restore(); | 1376 | state = state->restore(); |
1377 | out->restoreState(state); | 1377 | out->restoreState(state); |
1378 | 1378 | ||
1379 | delete shading; | 1379 | delete shading; |
1380 | } | 1380 | } |
1381 | 1381 | ||
1382 | void Gfx::doAxialShFill(GfxAxialShading *shading) { | 1382 | void Gfx::doAxialShFill(GfxAxialShading *shading) { |
1383 | fouble xMin, yMin, xMax, yMax; | 1383 | fouble xMin, yMin, xMax, yMax; |
1384 | fouble x0, y0, x1, y1; | 1384 | fouble x0, y0, x1, y1; |
1385 | fouble dx, dy, mul; | 1385 | fouble dx, dy, mul; |
1386 | fouble tMin, tMax, t, tx, ty; | 1386 | fouble tMin, tMax, t, tx, ty; |
1387 | fouble s[4], sMin, sMax, tmp; | 1387 | fouble s[4], sMin, sMax, tmp; |
1388 | fouble ux0, uy0, ux1, uy1, vx0, vy0, vx1, vy1; | 1388 | fouble ux0, uy0, ux1, uy1, vx0, vy0, vx1, vy1; |
1389 | fouble t0, t1, tt; | 1389 | fouble t0, t1, tt; |
1390 | fouble ta[axialMaxSplits + 1]; | 1390 | fouble ta[axialMaxSplits + 1]; |
1391 | int next[axialMaxSplits + 1]; | 1391 | int next[axialMaxSplits + 1]; |
1392 | GfxColor color0, color1; | 1392 | GfxColor color0, color1; |
1393 | int nComps; | 1393 | int nComps; |
1394 | int i, j, k, kk; | 1394 | int i, j, k, kk; |
1395 | 1395 | ||
1396 | // get the clip region bbox | 1396 | // get the clip region bbox |
1397 | state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); | 1397 | state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); |
1398 | 1398 | ||
1399 | // compute min and max t values, based on the four corners of the | 1399 | // compute min and max t values, based on the four corners of the |
1400 | // clip region bbox | 1400 | // clip region bbox |
1401 | shading->getCoords(&x0, &y0, &x1, &y1); | 1401 | shading->getCoords(&x0, &y0, &x1, &y1); |
1402 | dx = x1 - x0; | 1402 | dx = x1 - x0; |
1403 | dy = y1 - y0; | 1403 | dy = y1 - y0; |
1404 | mul = 1 / (dx * dx + dy * dy); | 1404 | mul = 1 / (dx * dx + dy * dy); |
1405 | tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul; | 1405 | tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul; |
1406 | t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul; | 1406 | t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul; |
1407 | if (t < tMin) { | 1407 | if (t < tMin) { |
1408 | tMin = t; | 1408 | tMin = t; |
1409 | } else if (t > tMax) { | 1409 | } else if (t > tMax) { |
1410 | tMax = t; | 1410 | tMax = t; |
1411 | } | 1411 | } |
1412 | t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul; | 1412 | t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul; |
1413 | if (t < tMin) { | 1413 | if (t < tMin) { |
1414 | tMin = t; | 1414 | tMin = t; |
1415 | } else if (t > tMax) { | 1415 | } else if (t > tMax) { |
1416 | tMax = t; | 1416 | tMax = t; |
1417 | } | 1417 | } |
1418 | t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul; | 1418 | t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul; |
1419 | if (t < tMin) { | 1419 | if (t < tMin) { |
1420 | tMin = t; | 1420 | tMin = t; |
1421 | } else if (t > tMax) { | 1421 | } else if (t > tMax) { |
1422 | tMax = t; | 1422 | tMax = t; |
1423 | } | 1423 | } |
1424 | if (tMin < 0 && !shading->getExtend0()) { | 1424 | if (tMin < 0 && !shading->getExtend0()) { |
1425 | tMin = 0; | 1425 | tMin = 0; |
1426 | } | 1426 | } |
1427 | if (tMax > 1 && !shading->getExtend1()) { | 1427 | if (tMax > 1 && !shading->getExtend1()) { |
1428 | tMax = 1; | 1428 | tMax = 1; |
1429 | } | 1429 | } |
1430 | 1430 | ||
1431 | // get the function domain | 1431 | // get the function domain |
1432 | t0 = shading->getDomain0(); | 1432 | t0 = shading->getDomain0(); |
1433 | t1 = shading->getDomain1(); | 1433 | t1 = shading->getDomain1(); |
1434 | 1434 | ||
1435 | // Traverse the t axis and do the shading. | 1435 | // Traverse the t axis and do the shading. |
1436 | // | 1436 | // |
1437 | // For each point (tx, ty) on the t axis, consider a line through | 1437 | // For each point (tx, ty) on the t axis, consider a line through |
1438 | // that point perpendicular to the t axis: | 1438 | // that point perpendicular to the t axis: |
1439 | // | 1439 | // |
1440 | // x(s) = tx + s * -dy --> s = (x - tx) / -dy | 1440 | // x(s) = tx + s * -dy --> s = (x - tx) / -dy |
1441 | // y(s) = ty + s * dx --> s = (y - ty) / dx | 1441 | // y(s) = ty + s * dx --> s = (y - ty) / dx |
1442 | // | 1442 | // |
1443 | // Then look at the intersection of this line with the bounding box | 1443 | // Then look at the intersection of this line with the bounding box |
1444 | // (xMin, yMin, xMax, yMax). In the general case, there are four | 1444 | // (xMin, yMin, xMax, yMax). In the general case, there are four |
1445 | // intersection points: | 1445 | // intersection points: |
1446 | // | 1446 | // |
1447 | // s0 = (xMin - tx) / -dy | 1447 | // s0 = (xMin - tx) / -dy |
1448 | // s1 = (xMax - tx) / -dy | 1448 | // s1 = (xMax - tx) / -dy |
1449 | // s2 = (yMin - ty) / dx | 1449 | // s2 = (yMin - ty) / dx |
1450 | // s3 = (yMax - ty) / dx | 1450 | // s3 = (yMax - ty) / dx |
1451 | // | 1451 | // |
1452 | // and we want the middle two s values. | 1452 | // and we want the middle two s values. |
1453 | // | 1453 | // |
1454 | // In the case where dx = 0, take s0 and s1; in the case where dy = | 1454 | // In the case where dx = 0, take s0 and s1; in the case where dy = |
1455 | // 0, take s2 and s3. | 1455 | // 0, take s2 and s3. |
1456 | // | 1456 | // |
1457 | // Each filled polygon is bounded by two of these line segments | 1457 | // Each filled polygon is bounded by two of these line segments |
1458 | // perpdendicular to the t axis. | 1458 | // perpdendicular to the t axis. |
1459 | // | 1459 | // |
1460 | // The t axis is bisected into smaller regions until the color | 1460 | // The t axis is bisected into smaller regions until the color |
1461 | // difference across a region is small enough, and then the region | 1461 | // difference across a region is small enough, and then the region |
1462 | // is painted with a single color. | 1462 | // is painted with a single color. |
1463 | 1463 | ||
1464 | // set up | 1464 | // set up |
1465 | nComps = shading->getColorSpace()->getNComps(); | 1465 | nComps = shading->getColorSpace()->getNComps(); |
1466 | ta[0] = tMin; | 1466 | ta[0] = tMin; |
1467 | ta[axialMaxSplits] = tMax; | 1467 | ta[axialMaxSplits] = tMax; |
1468 | next[0] = axialMaxSplits; | 1468 | next[0] = axialMaxSplits; |
1469 | 1469 | ||
1470 | // compute the color at t = tMin | 1470 | // compute the color at t = tMin |
1471 | if (tMin < 0) { | 1471 | if (tMin < 0) { |
1472 | tt = t0; | 1472 | tt = t0; |
1473 | } else if (tMin > 1) { | 1473 | } else if (tMin > 1) { |
1474 | tt = t1; | 1474 | tt = t1; |
1475 | } else { | 1475 | } else { |
1476 | tt = t0 + (t1 - t0) * tMin; | 1476 | tt = t0 + (t1 - t0) * tMin; |
1477 | } | 1477 | } |
1478 | shading->getColor(tt, &color0); | 1478 | shading->getColor(tt, &color0); |
1479 | 1479 | ||
1480 | // compute the coordinates of the point on the t axis at t = tMin; | 1480 | // compute the coordinates of the point on the t axis at t = tMin; |
1481 | // then compute the intersection of the perpendicular line with the | 1481 | // then compute the intersection of the perpendicular line with the |
1482 | // bounding box | 1482 | // bounding box |
1483 | tx = x0 + tMin * dx; | 1483 | tx = x0 + tMin * dx; |
1484 | ty = y0 + tMin * dy; | 1484 | ty = y0 + tMin * dy; |
1485 | if (dx == 0 && dy == 0) { | 1485 | if (dx == 0 && dy == 0) { |
1486 | sMin = sMax = 0; | 1486 | sMin = sMax = 0; |
1487 | } if (dx == 0) { | 1487 | } if (dx == 0) { |
1488 | sMin = (xMin - tx) / -dy; | 1488 | sMin = (xMin - tx) / -dy; |
1489 | sMax = (xMax - tx) / -dy; | 1489 | sMax = (xMax - tx) / -dy; |
1490 | if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } | 1490 | if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } |
1491 | } else if (dy == 0) { | 1491 | } else if (dy == 0) { |
1492 | sMin = (yMin - ty) / dx; | 1492 | sMin = (yMin - ty) / dx; |
1493 | sMax = (yMax - ty) / dx; | 1493 | sMax = (yMax - ty) / dx; |
1494 | if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } | 1494 | if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } |
1495 | } else { | 1495 | } else { |
1496 | s[0] = (yMin - ty) / dx; | 1496 | s[0] = (yMin - ty) / dx; |
1497 | s[1] = (yMax - ty) / dx; | 1497 | s[1] = (yMax - ty) / dx; |
1498 | s[2] = (xMin - tx) / -dy; | 1498 | s[2] = (xMin - tx) / -dy; |
1499 | s[3] = (xMax - tx) / -dy; | 1499 | s[3] = (xMax - tx) / -dy; |
1500 | for (j = 0; j < 3; ++j) { | 1500 | for (j = 0; j < 3; ++j) { |
1501 | kk = j; | 1501 | kk = j; |
1502 | for (k = j + 1; k < 4; ++k) { | 1502 | for (k = j + 1; k < 4; ++k) { |
1503 | if (s[k] < s[kk]) { | 1503 | if (s[k] < s[kk]) { |
1504 | kk = k; | 1504 | kk = k; |
1505 | } | 1505 | } |
1506 | } | 1506 | } |
1507 | tmp = s[j]; s[j] = s[kk]; s[kk] = tmp; | 1507 | tmp = s[j]; s[j] = s[kk]; s[kk] = tmp; |
1508 | } | 1508 | } |
1509 | sMin = s[1]; | 1509 | sMin = s[1]; |
1510 | sMax = s[2]; | 1510 | sMax = s[2]; |
1511 | } | 1511 | } |
1512 | ux0 = tx - sMin * dy; | 1512 | ux0 = tx - sMin * dy; |
1513 | uy0 = ty + sMin * dx; | 1513 | uy0 = ty + sMin * dx; |
1514 | vx0 = tx - sMax * dy; | 1514 | vx0 = tx - sMax * dy; |
1515 | vy0 = ty + sMax * dx; | 1515 | vy0 = ty + sMax * dx; |
1516 | 1516 | ||
1517 | i = 0; | 1517 | i = 0; |
1518 | while (i < axialMaxSplits) { | 1518 | while (i < axialMaxSplits) { |
1519 | 1519 | ||
1520 | // bisect until color difference is small enough or we hit the | 1520 | // bisect until color difference is small enough or we hit the |
1521 | // bisection limit | 1521 | // bisection limit |
1522 | j = next[i]; | 1522 | j = next[i]; |
1523 | while (j > i + 1) { | 1523 | while (j > i + 1) { |
1524 | if (ta[j] < 0) { | 1524 | if (ta[j] < 0) { |
1525 | tt = t0; | 1525 | tt = t0; |
1526 | } else if (ta[j] > 1) { | 1526 | } else if (ta[j] > 1) { |
1527 | tt = t1; | 1527 | tt = t1; |
1528 | } else { | 1528 | } else { |
1529 | tt = t0 + (t1 - t0) * ta[j]; | 1529 | tt = t0 + (t1 - t0) * ta[j]; |
1530 | } | 1530 | } |
1531 | shading->getColor(tt, &color1); | 1531 | shading->getColor(tt, &color1); |
1532 | for (k = 0; k < nComps; ++k) { | 1532 | for (k = 0; k < nComps; ++k) { |
1533 | if (fabs(color1.c[k] - color0.c[k]) > axialColorDelta) { | 1533 | if (fabs(color1.c[k] - color0.c[k]) > axialColorDelta) { |
1534 | break; | 1534 | break; |
1535 | } | 1535 | } |
1536 | } | 1536 | } |
1537 | if (k == nComps) { | 1537 | if (k == nComps) { |
1538 | break; | 1538 | break; |
1539 | } | 1539 | } |
1540 | k = (i + j) / 2; | 1540 | k = (i + j) / 2; |
1541 | ta[k] = 0.5 * (ta[i] + ta[j]); | 1541 | ta[k] = 0.5 * (ta[i] + ta[j]); |
1542 | next[i] = k; | 1542 | next[i] = k; |
1543 | next[k] = j; | 1543 | next[k] = j; |
1544 | j = k; | 1544 | j = k; |
1545 | } | 1545 | } |
1546 | 1546 | ||
1547 | // use the average of the colors of the two sides of the region | 1547 | // use the average of the colors of the two sides of the region |
1548 | for (k = 0; k < nComps; ++k) { | 1548 | for (k = 0; k < nComps; ++k) { |
1549 | color0.c[k] = 0.5 * (color0.c[k] + color1.c[k]); | 1549 | color0.c[k] = 0.5 * (color0.c[k] + color1.c[k]); |
1550 | } | 1550 | } |
1551 | 1551 | ||
1552 | // compute the coordinates of the point on the t axis; then | 1552 | // compute the coordinates of the point on the t axis; then |
1553 | // compute the intersection of the perpendicular line with the | 1553 | // compute the intersection of the perpendicular line with the |
1554 | // bounding box | 1554 | // bounding box |
1555 | tx = x0 + ta[j] * dx; | 1555 | tx = x0 + ta[j] * dx; |
1556 | ty = y0 + ta[j] * dy; | 1556 | ty = y0 + ta[j] * dy; |
1557 | if (dx == 0 && dy == 0) { | 1557 | if (dx == 0 && dy == 0) { |
1558 | sMin = sMax = 0; | 1558 | sMin = sMax = 0; |
1559 | } if (dx == 0) { | 1559 | } if (dx == 0) { |
1560 | sMin = (xMin - tx) / -dy; | 1560 | sMin = (xMin - tx) / -dy; |
1561 | sMax = (xMax - tx) / -dy; | 1561 | sMax = (xMax - tx) / -dy; |
1562 | if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } | 1562 | if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } |
1563 | } else if (dy == 0) { | 1563 | } else if (dy == 0) { |
1564 | sMin = (yMin - ty) / dx; | 1564 | sMin = (yMin - ty) / dx; |
1565 | sMax = (yMax - ty) / dx; | 1565 | sMax = (yMax - ty) / dx; |
1566 | if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } | 1566 | if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } |
1567 | } else { | 1567 | } else { |
1568 | s[0] = (yMin - ty) / dx; | 1568 | s[0] = (yMin - ty) / dx; |
1569 | s[1] = (yMax - ty) / dx; | 1569 | s[1] = (yMax - ty) / dx; |
1570 | s[2] = (xMin - tx) / -dy; | 1570 | s[2] = (xMin - tx) / -dy; |
1571 | s[3] = (xMax - tx) / -dy; | 1571 | s[3] = (xMax - tx) / -dy; |
1572 | for (j = 0; j < 3; ++j) { | 1572 | for (j = 0; j < 3; ++j) { |
1573 | kk = j; | 1573 | kk = j; |
1574 | for (k = j + 1; k < 4; ++k) { | 1574 | for (k = j + 1; k < 4; ++k) { |
1575 | if (s[k] < s[kk]) { | 1575 | if (s[k] < s[kk]) { |
1576 | kk = k; | 1576 | kk = k; |
1577 | } | 1577 | } |
1578 | } | 1578 | } |
1579 | tmp = s[j]; s[j] = s[kk]; s[kk] = tmp; | 1579 | tmp = s[j]; s[j] = s[kk]; s[kk] = tmp; |
1580 | } | 1580 | } |
1581 | sMin = s[1]; | 1581 | sMin = s[1]; |
1582 | sMax = s[2]; | 1582 | sMax = s[2]; |
1583 | } | 1583 | } |
1584 | ux1 = tx - sMin * dy; | 1584 | ux1 = tx - sMin * dy; |
1585 | uy1 = ty + sMin * dx; | 1585 | uy1 = ty + sMin * dx; |
1586 | vx1 = tx - sMax * dy; | 1586 | vx1 = tx - sMax * dy; |
1587 | vy1 = ty + sMax * dx; | 1587 | vy1 = ty + sMax * dx; |
1588 | 1588 | ||
1589 | // set the color | 1589 | // set the color |
1590 | state->setFillColor(&color0); | 1590 | state->setFillColor(&color0); |
1591 | out->updateFillColor(state); | 1591 | out->updateFillColor(state); |
1592 | 1592 | ||
1593 | // fill the region | 1593 | // fill the region |
1594 | state->moveTo(ux0, uy0); | 1594 | state->moveTo(ux0, uy0); |
1595 | state->lineTo(vx0, vy0); | 1595 | state->lineTo(vx0, vy0); |
1596 | state->lineTo(vx1, vy1); | 1596 | state->lineTo(vx1, vy1); |
1597 | state->lineTo(ux1, uy1); | 1597 | state->lineTo(ux1, uy1); |
1598 | state->closePath(); | 1598 | state->closePath(); |
1599 | out->fill(state); | 1599 | out->fill(state); |
1600 | state->clearPath(); | 1600 | state->clearPath(); |
1601 | 1601 | ||
1602 | // set up for next region | 1602 | // set up for next region |
1603 | ux0 = ux1; | 1603 | ux0 = ux1; |
1604 | uy0 = uy1; | 1604 | uy0 = uy1; |
1605 | vx0 = vx1; | 1605 | vx0 = vx1; |
1606 | vy0 = vy1; | 1606 | vy0 = vy1; |
1607 | color0 = color1; | 1607 | color0 = color1; |
1608 | i = next[i]; | 1608 | i = next[i]; |
1609 | } | 1609 | } |
1610 | } | 1610 | } |
1611 | 1611 | ||
1612 | void Gfx::doRadialShFill(GfxRadialShading *shading) { | 1612 | void Gfx::doRadialShFill(GfxRadialShading *shading) { |
1613 | fouble sMin, sMax, xMin, yMin, xMax, yMax; | 1613 | fouble sMin, sMax, xMin, yMin, xMax, yMax; |
1614 | fouble x0, y0, r0, x1, y1, r1, t0, t1; | 1614 | fouble x0, y0, r0, x1, y1, r1, t0, t1; |
1615 | int nComps; | 1615 | int nComps; |
1616 | GfxColor colorA, colorB; | 1616 | GfxColor colorA, colorB; |
1617 | fouble xa, ya, xb, yb, ra, rb; | 1617 | fouble xa, ya, xb, yb, ra, rb; |
1618 | fouble ta, tb, sa, sb; | 1618 | fouble ta, tb, sa, sb; |
1619 | int ia, ib, k, n; | 1619 | int ia, ib, k, n; |
1620 | fouble *ctm; | 1620 | fouble *ctm; |
1621 | fouble angle, t; | 1621 | fouble angle, t; |
1622 | 1622 | ||
1623 | // get the shading info | 1623 | // get the shading info |
1624 | shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1); | 1624 | shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1); |
1625 | t0 = shading->getDomain0(); | 1625 | t0 = shading->getDomain0(); |
1626 | t1 = shading->getDomain1(); | 1626 | t1 = shading->getDomain1(); |
1627 | nComps = shading->getColorSpace()->getNComps(); | 1627 | nComps = shading->getColorSpace()->getNComps(); |
1628 | 1628 | ||
1629 | // compute the (possibly extended) s range | 1629 | // compute the (possibly extended) s range |
1630 | sMin = 0; | 1630 | sMin = 0; |
1631 | sMax = 1; | 1631 | sMax = 1; |
1632 | if (shading->getExtend0()) { | 1632 | if (shading->getExtend0()) { |
1633 | if (r0 < r1) { | 1633 | if (r0 < r1) { |
1634 | // extend the smaller end | 1634 | // extend the smaller end |
1635 | sMin = -r0 / (r1 - r0); | 1635 | sMin = -r0 / (r1 - r0); |
1636 | } else { | 1636 | } else { |
1637 | // extend the larger end | 1637 | // extend the larger end |
1638 | //~ this computes the diagonal of the bounding box -- we should | 1638 | //~ this computes the diagonal of the bounding box -- we should |
1639 | //~ really compute the intersection of the moving/expanding | 1639 | //~ really compute the intersection of the moving/expanding |
1640 | //~ circles with each of the four corners and look for the max | 1640 | //~ circles with each of the four corners and look for the max |
1641 | //~ radius | 1641 | //~ radius |
1642 | state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); | 1642 | state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); |
1643 | sMin = (sqrt((xMax - xMin) * (xMax - xMin) + | 1643 | sMin = (sqrt((xMax - xMin) * (xMax - xMin) + |
1644 | (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0); | 1644 | (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0); |
1645 | if (sMin > 0) { | 1645 | if (sMin > 0) { |
1646 | sMin = 0; | 1646 | sMin = 0; |
1647 | } else if (sMin < -20) { | 1647 | } else if (sMin < -20) { |
1648 | // sanity check | 1648 | // sanity check |
1649 | sMin = -20; | 1649 | sMin = -20; |
1650 | } | 1650 | } |
1651 | } | 1651 | } |
1652 | } | 1652 | } |
1653 | if (shading->getExtend1()) { | 1653 | if (shading->getExtend1()) { |
1654 | if (r1 < r0) { | 1654 | if (r1 < r0) { |
1655 | // extend the smaller end | 1655 | // extend the smaller end |
1656 | sMax = -r0 / (r1 - r0); | 1656 | sMax = -r0 / (r1 - r0); |
1657 | } else if (r1 > r0) { | 1657 | } else if (r1 > r0) { |
1658 | // extend the larger end | 1658 | // extend the larger end |
1659 | state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); | 1659 | state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); |
1660 | sMax = (sqrt((xMax - xMin) * (xMax - xMin) + | 1660 | sMax = (sqrt((xMax - xMin) * (xMax - xMin) + |
1661 | (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0); | 1661 | (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0); |
1662 | if (sMax < 1) { | 1662 | if (sMax < 1) { |
1663 | sMin = 1; | 1663 | sMin = 1; |
1664 | } else if (sMax > 20) { | 1664 | } else if (sMax > 20) { |
1665 | // sanity check | 1665 | // sanity check |
1666 | sMax = 20; | 1666 | sMax = 20; |
1667 | } | 1667 | } |
1668 | } | 1668 | } |
1669 | } | 1669 | } |
1670 | 1670 | ||
1671 | // compute the number of steps into which circles must be divided to | 1671 | // compute the number of steps into which circles must be divided to |
1672 | // achieve a curve flatness of 0.1 pixel in device space for the | 1672 | // achieve a curve flatness of 0.1 pixel in device space for the |
1673 | // largest circle (note that "device space" is 72 dpi when generating | 1673 | // largest circle (note that "device space" is 72 dpi when generating |
1674 | // PostScript, hence the relatively small 0.1 pixel accuracy) | 1674 | // PostScript, hence the relatively small 0.1 pixel accuracy) |
1675 | ctm = state->getCTM(); | 1675 | ctm = state->getCTM(); |
1676 | t = fabs(ctm[0]); | 1676 | t = fabs(ctm[0]); |
1677 | if (fabs(ctm[1]) > t) { | 1677 | if (fabs(ctm[1]) > t) { |
1678 | t = fabs(ctm[1]); | 1678 | t = fabs(ctm[1]); |
1679 | } | 1679 | } |
1680 | if (fabs(ctm[2]) > t) { | 1680 | if (fabs(ctm[2]) > t) { |
1681 | t = fabs(ctm[2]); | 1681 | t = fabs(ctm[2]); |
1682 | } | 1682 | } |
1683 | if (fabs(ctm[3]) > t) { | 1683 | if (fabs(ctm[3]) > t) { |
1684 | t = fabs(ctm[3]); | 1684 | t = fabs(ctm[3]); |
1685 | } | 1685 | } |
1686 | if (r0 > r1) { | 1686 | if (r0 > r1) { |
1687 | t *= r0; | 1687 | t *= r0; |
1688 | } else { | 1688 | } else { |
1689 | t *= r1; | 1689 | t *= r1; |
1690 | } | 1690 | } |
1691 | if (t < 1) { | 1691 | if (t < 1) { |
1692 | n = 3; | 1692 | n = 3; |
1693 | } else { | 1693 | } else { |
1694 | n = (int)(M_PI / acos(1 - 0.1 / t)); | 1694 | n = (int)(M_PI / acos(1 - 0.1 / t)); |
1695 | if (n < 3) { | 1695 | if (n < 3) { |
1696 | n = 3; | 1696 | n = 3; |
1697 | } else if (n > 200) { | 1697 | } else if (n > 200) { |
1698 | n = 200; | 1698 | n = 200; |
1699 | } | 1699 | } |
1700 | } | 1700 | } |
1701 | 1701 | ||
1702 | // Traverse the t axis and do the shading. | 1702 | // Traverse the t axis and do the shading. |
1703 | // | 1703 | // |
1704 | // This generates and fills a series of rings. Each ring is defined | 1704 | // This generates and fills a series of rings. Each ring is defined |
1705 | // by two circles: | 1705 | // by two circles: |
1706 | // sa, ta, xa, ya, ra, colorA | 1706 | // sa, ta, xa, ya, ra, colorA |
1707 | // sb, tb, xb, yb, rb, colorB | 1707 | // sb, tb, xb, yb, rb, colorB |
1708 | // | 1708 | // |
1709 | // The s/t axis is divided into radialMaxSplits parts; these parts | 1709 | // The s/t axis is divided into radialMaxSplits parts; these parts |
1710 | // are combined as much as possible while respecting the | 1710 | // are combined as much as possible while respecting the |
1711 | // radialColorDelta parameter. | 1711 | // radialColorDelta parameter. |
1712 | 1712 | ||
1713 | // setup for the start circle | 1713 | // setup for the start circle |
1714 | ia = 0; | 1714 | ia = 0; |
1715 | sa = sMin; | 1715 | sa = sMin; |
1716 | ta = t0 + sa * (t1 - t0); | 1716 | ta = t0 + sa * (t1 - t0); |
1717 | xa = x0 + sa * (x1 - x0); | 1717 | xa = x0 + sa * (x1 - x0); |
1718 | ya = y0 + sa * (y1 - y0); | 1718 | ya = y0 + sa * (y1 - y0); |
1719 | ra = r0 + sa * (r1 - r0); | 1719 | ra = r0 + sa * (r1 - r0); |
1720 | if (ta < t0) { | 1720 | if (ta < t0) { |
1721 | shading->getColor(t0, &colorA); | 1721 | shading->getColor(t0, &colorA); |
1722 | } else if (ta > t1) { | 1722 | } else if (ta > t1) { |
1723 | shading->getColor(t1, &colorA); | 1723 | shading->getColor(t1, &colorA); |
1724 | } else { | 1724 | } else { |
1725 | shading->getColor(ta, &colorA); | 1725 | shading->getColor(ta, &colorA); |
1726 | } | 1726 | } |
1727 | 1727 | ||
1728 | while (ia < radialMaxSplits) { | 1728 | while (ia < radialMaxSplits) { |
1729 | 1729 | ||
1730 | // go as far along the t axis (toward t1) as we can, such that the | 1730 | // go as far along the t axis (toward t1) as we can, such that the |
1731 | // color difference is within the tolerance (radialColorDelta) -- | 1731 | // color difference is within the tolerance (radialColorDelta) -- |
1732 | // this uses bisection (between the current value, t, and t1), | 1732 | // this uses bisection (between the current value, t, and t1), |
1733 | // limited to radialMaxSplits points along the t axis | 1733 | // limited to radialMaxSplits points along the t axis |
1734 | ib = radialMaxSplits; | 1734 | ib = radialMaxSplits; |
1735 | sb = sMin + ((fouble)ib / (fouble)radialMaxSplits) * (sMax - sMin); | 1735 | sb = sMin + ((fouble)ib / (fouble)radialMaxSplits) * (sMax - sMin); |
1736 | tb = t0 + sb * (t1 - t0); | 1736 | tb = t0 + sb * (t1 - t0); |
1737 | if (tb < t0) { | 1737 | if (tb < t0) { |
1738 | shading->getColor(t0, &colorB); | 1738 | shading->getColor(t0, &colorB); |
1739 | } else if (tb > t1) { | 1739 | } else if (tb > t1) { |
1740 | shading->getColor(t1, &colorB); | 1740 | shading->getColor(t1, &colorB); |
1741 | } else { | 1741 | } else { |
1742 | shading->getColor(tb, &colorB); | 1742 | shading->getColor(tb, &colorB); |
1743 | } | 1743 | } |
1744 | while (ib - ia > 1) { | 1744 | while (ib - ia > 1) { |
1745 | for (k = 0; k < nComps; ++k) { | 1745 | for (k = 0; k < nComps; ++k) { |
1746 | if (fabs(colorB.c[k] - colorA.c[k]) > radialColorDelta) { | 1746 | if (fabs(colorB.c[k] - colorA.c[k]) > radialColorDelta) { |
1747 | break; | 1747 | break; |
1748 | } | 1748 | } |
1749 | } | 1749 | } |
1750 | if (k == nComps) { | 1750 | if (k == nComps) { |
1751 | break; | 1751 | break; |
1752 | } | 1752 | } |
1753 | ib = (ia + ib) / 2; | 1753 | ib = (ia + ib) / 2; |
1754 | sb = sMin + ((fouble)ib / (fouble)radialMaxSplits) * (sMax - sMin); | 1754 | sb = sMin + ((fouble)ib / (fouble)radialMaxSplits) * (sMax - sMin); |
1755 | tb = t0 + sb * (t1 - t0); | 1755 | tb = t0 + sb * (t1 - t0); |
1756 | if (tb < t0) { | 1756 | if (tb < t0) { |
1757 | shading->getColor(t0, &colorB); | 1757 | shading->getColor(t0, &colorB); |
1758 | } else if (tb > t1) { | 1758 | } else if (tb > t1) { |
1759 | shading->getColor(t1, &colorB); | 1759 | shading->getColor(t1, &colorB); |
1760 | } else { | 1760 | } else { |
1761 | shading->getColor(tb, &colorB); | 1761 | shading->getColor(tb, &colorB); |
1762 | } | 1762 | } |
1763 | } | 1763 | } |
1764 | 1764 | ||
1765 | // compute center and radius of the circle | 1765 | // compute center and radius of the circle |
1766 | xb = x0 + sb * (x1 - x0); | 1766 | xb = x0 + sb * (x1 - x0); |
1767 | yb = y0 + sb * (y1 - y0); | 1767 | yb = y0 + sb * (y1 - y0); |
1768 | rb = r0 + sb * (r1 - r0); | 1768 | rb = r0 + sb * (r1 - r0); |
1769 | 1769 | ||
1770 | // use the average of the colors at the two circles | 1770 | // use the average of the colors at the two circles |
1771 | for (k = 0; k < nComps; ++k) { | 1771 | for (k = 0; k < nComps; ++k) { |
1772 | colorA.c[k] = 0.5 * (colorA.c[k] + colorB.c[k]); | 1772 | colorA.c[k] = 0.5 * (colorA.c[k] + colorB.c[k]); |
1773 | } | 1773 | } |
1774 | state->setFillColor(&colorA); | 1774 | state->setFillColor(&colorA); |
1775 | out->updateFillColor(state); | 1775 | out->updateFillColor(state); |
1776 | 1776 | ||
1777 | // construct path for first circle | 1777 | // construct path for first circle |
1778 | state->moveTo(xa + ra, ya); | 1778 | state->moveTo(xa + ra, ya); |
1779 | for (k = 1; k < n; ++k) { | 1779 | for (k = 1; k < n; ++k) { |
1780 | angle = ((fouble)k / (fouble)n) * 2 * M_PI; | 1780 | angle = ((fouble)k / (fouble)n) * 2 * M_PI; |
1781 | state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle)); | 1781 | state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle)); |
1782 | } | 1782 | } |
1783 | state->closePath(); | 1783 | state->closePath(); |
1784 | 1784 | ||
1785 | // construct and append path for second circle | 1785 | // construct and append path for second circle |
1786 | state->moveTo(xb + rb, yb); | 1786 | state->moveTo(xb + rb, yb); |
1787 | for (k = 1; k < n; ++k) { | 1787 | for (k = 1; k < n; ++k) { |
1788 | angle = ((fouble)k / (fouble)n) * 2 * M_PI; | 1788 | angle = ((fouble)k / (fouble)n) * 2 * M_PI; |
1789 | state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle)); | 1789 | state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle)); |
1790 | } | 1790 | } |
1791 | state->closePath(); | 1791 | state->closePath(); |
1792 | 1792 | ||
1793 | // fill the ring | 1793 | // fill the ring |
1794 | out->eoFill(state); | 1794 | out->eoFill(state); |
1795 | state->clearPath(); | 1795 | state->clearPath(); |
1796 | 1796 | ||
1797 | // step to the next value of t | 1797 | // step to the next value of t |
1798 | ia = ib; | 1798 | ia = ib; |
1799 | sa = sb; | 1799 | sa = sb; |
1800 | ta = tb; | 1800 | ta = tb; |
1801 | xa = xb; | 1801 | xa = xb; |
1802 | ya = yb; | 1802 | ya = yb; |
1803 | ra = rb; | 1803 | ra = rb; |
1804 | colorA = colorB; | 1804 | colorA = colorB; |
1805 | } | 1805 | } |
1806 | } | 1806 | } |
1807 | 1807 | ||
1808 | void Gfx::doEndPath() { | 1808 | void Gfx::doEndPath() { |
1809 | if (state->isPath() && clip != clipNone) { | 1809 | if (state->isPath() && clip != clipNone) { |
1810 | state->clip(); | 1810 | state->clip(); |
1811 | if (clip == clipNormal) { | 1811 | if (clip == clipNormal) { |
1812 | out->clip(state); | 1812 | out->clip(state); |
1813 | } else { | 1813 | } else { |
1814 | out->eoClip(state); | 1814 | out->eoClip(state); |
1815 | } | 1815 | } |
1816 | } | 1816 | } |
1817 | clip = clipNone; | 1817 | clip = clipNone; |
1818 | state->clearPath(); | 1818 | state->clearPath(); |
1819 | } | 1819 | } |
1820 | 1820 | ||
1821 | //------------------------------------------------------------------------ | 1821 | //------------------------------------------------------------------------ |
1822 | // path clipping operators | 1822 | // path clipping operators |
1823 | //------------------------------------------------------------------------ | 1823 | //------------------------------------------------------------------------ |
1824 | 1824 | ||
1825 | void Gfx::opClip(Object args[], int numArgs) { | 1825 | void Gfx::opClip(Object args[], int numArgs) { |
1826 | clip = clipNormal; | 1826 | clip = clipNormal; |
1827 | } | 1827 | } |
1828 | 1828 | ||
1829 | void Gfx::opEOClip(Object args[], int numArgs) { | 1829 | void Gfx::opEOClip(Object args[], int numArgs) { |
1830 | clip = clipEO; | 1830 | clip = clipEO; |
1831 | } | 1831 | } |
1832 | 1832 | ||
1833 | //------------------------------------------------------------------------ | 1833 | //------------------------------------------------------------------------ |
1834 | // text object operators | 1834 | // text object operators |
1835 | //------------------------------------------------------------------------ | 1835 | //------------------------------------------------------------------------ |
1836 | 1836 | ||
1837 | void Gfx::opBeginText(Object args[], int numArgs) { | 1837 | void Gfx::opBeginText(Object args[], int numArgs) { |
1838 | state->setTextMat(1, 0, 0, 1, 0, 0); | 1838 | state->setTextMat(1, 0, 0, 1, 0, 0); |
1839 | state->textMoveTo(0, 0); | 1839 | state->textMoveTo(0, 0); |
1840 | out->updateTextMat(state); | 1840 | out->updateTextMat(state); |
1841 | out->updateTextPos(state); | 1841 | out->updateTextPos(state); |
1842 | fontChanged = gTrue; | 1842 | fontChanged = gTrue; |
1843 | } | 1843 | } |
1844 | 1844 | ||
1845 | void Gfx::opEndText(Object args[], int numArgs) { | 1845 | void Gfx::opEndText(Object args[], int numArgs) { |
1846 | } | 1846 | } |
1847 | 1847 | ||
1848 | //------------------------------------------------------------------------ | 1848 | //------------------------------------------------------------------------ |
1849 | // text state operators | 1849 | // text state operators |
1850 | //------------------------------------------------------------------------ | 1850 | //------------------------------------------------------------------------ |
1851 | 1851 | ||
1852 | void Gfx::opSetCharSpacing(Object args[], int numArgs) { | 1852 | void Gfx::opSetCharSpacing(Object args[], int numArgs) { |
1853 | state->setCharSpace(args[0].getNum()); | 1853 | state->setCharSpace(args[0].getNum()); |
1854 | out->updateCharSpace(state); | 1854 | out->updateCharSpace(state); |
1855 | } | 1855 | } |
1856 | 1856 | ||
1857 | void Gfx::opSetFont(Object args[], int numArgs) { | 1857 | void Gfx::opSetFont(Object args[], int numArgs) { |
1858 | GfxFont *font; | 1858 | GfxFont *font; |
1859 | 1859 | ||
1860 | if (!(font = res->lookupFont(args[0].getName()))) { | 1860 | if (!(font = res->lookupFont(args[0].getName()))) { |
1861 | return; | 1861 | return; |
1862 | } | 1862 | } |
1863 | if (printCommands) { | 1863 | if (printCommands) { |
1864 | printf(" font: tag=%s name='%s' %g\n", | 1864 | printf(" font: tag=%s name='%s' %g\n", |
1865 | font->getTag()->getCString(), | 1865 | font->getTag()->getCString(), |
1866 | font->getName() ? font->getName()->getCString() : "???", | 1866 | font->getName() ? font->getName()->getCString() : "???", |
1867 | args[1].getNum()); | 1867 | static_cast<double>(args[1].getNum())); |
1868 | fflush(stdout); | 1868 | fflush(stdout); |
1869 | } | 1869 | } |
1870 | state->setFont(font, args[1].getNum()); | 1870 | state->setFont(font, args[1].getNum()); |
1871 | fontChanged = gTrue; | 1871 | fontChanged = gTrue; |
1872 | } | 1872 | } |
1873 | 1873 | ||
1874 | void Gfx::opSetTextLeading(Object args[], int numArgs) { | 1874 | void Gfx::opSetTextLeading(Object args[], int numArgs) { |
1875 | state->setLeading(args[0].getNum()); | 1875 | state->setLeading(args[0].getNum()); |
1876 | } | 1876 | } |
1877 | 1877 | ||
1878 | void Gfx::opSetTextRender(Object args[], int numArgs) { | 1878 | void Gfx::opSetTextRender(Object args[], int numArgs) { |
1879 | state->setRender(args[0].getInt()); | 1879 | state->setRender(args[0].getInt()); |
1880 | out->updateRender(state); | 1880 | out->updateRender(state); |
1881 | } | 1881 | } |
1882 | 1882 | ||
1883 | void Gfx::opSetTextRise(Object args[], int numArgs) { | 1883 | void Gfx::opSetTextRise(Object args[], int numArgs) { |
1884 | state->setRise(args[0].getNum()); | 1884 | state->setRise(args[0].getNum()); |
1885 | out->updateRise(state); | 1885 | out->updateRise(state); |
1886 | } | 1886 | } |
1887 | 1887 | ||
1888 | void Gfx::opSetWordSpacing(Object args[], int numArgs) { | 1888 | void Gfx::opSetWordSpacing(Object args[], int numArgs) { |
1889 | state->setWordSpace(args[0].getNum()); | 1889 | state->setWordSpace(args[0].getNum()); |
1890 | out->updateWordSpace(state); | 1890 | out->updateWordSpace(state); |
1891 | } | 1891 | } |
1892 | 1892 | ||
1893 | void Gfx::opSetHorizScaling(Object args[], int numArgs) { | 1893 | void Gfx::opSetHorizScaling(Object args[], int numArgs) { |
1894 | state->setHorizScaling(args[0].getNum()); | 1894 | state->setHorizScaling(args[0].getNum()); |
1895 | out->updateHorizScaling(state); | 1895 | out->updateHorizScaling(state); |
1896 | fontChanged = gTrue; | 1896 | fontChanged = gTrue; |
1897 | } | 1897 | } |
1898 | 1898 | ||
1899 | //------------------------------------------------------------------------ | 1899 | //------------------------------------------------------------------------ |
1900 | // text positioning operators | 1900 | // text positioning operators |
1901 | //------------------------------------------------------------------------ | 1901 | //------------------------------------------------------------------------ |
1902 | 1902 | ||
1903 | void Gfx::opTextMove(Object args[], int numArgs) { | 1903 | void Gfx::opTextMove(Object args[], int numArgs) { |
1904 | fouble tx, ty; | 1904 | fouble tx, ty; |
1905 | 1905 | ||
1906 | tx = state->getLineX() + args[0].getNum(); | 1906 | tx = state->getLineX() + args[0].getNum(); |
1907 | ty = state->getLineY() + args[1].getNum(); | 1907 | ty = state->getLineY() + args[1].getNum(); |
1908 | state->textMoveTo(tx, ty); | 1908 | state->textMoveTo(tx, ty); |
1909 | out->updateTextPos(state); | 1909 | out->updateTextPos(state); |
1910 | } | 1910 | } |
1911 | 1911 | ||
1912 | void Gfx::opTextMoveSet(Object args[], int numArgs) { | 1912 | void Gfx::opTextMoveSet(Object args[], int numArgs) { |
1913 | fouble tx, ty; | 1913 | fouble tx, ty; |
1914 | 1914 | ||
1915 | tx = state->getLineX() + args[0].getNum(); | 1915 | tx = state->getLineX() + args[0].getNum(); |
1916 | ty = args[1].getNum(); | 1916 | ty = args[1].getNum(); |
1917 | state->setLeading(-ty); | 1917 | state->setLeading(-ty); |
1918 | ty += state->getLineY(); | 1918 | ty += state->getLineY(); |
1919 | state->textMoveTo(tx, ty); | 1919 | state->textMoveTo(tx, ty); |
1920 | out->updateTextPos(state); | 1920 | out->updateTextPos(state); |
1921 | } | 1921 | } |
1922 | 1922 | ||
1923 | void Gfx::opSetTextMatrix(Object args[], int numArgs) { | 1923 | void Gfx::opSetTextMatrix(Object args[], int numArgs) { |
1924 | state->setTextMat(args[0].getNum(), args[1].getNum(), | 1924 | state->setTextMat(args[0].getNum(), args[1].getNum(), |
1925 | args[2].getNum(), args[3].getNum(), | 1925 | args[2].getNum(), args[3].getNum(), |
1926 | args[4].getNum(), args[5].getNum()); | 1926 | args[4].getNum(), args[5].getNum()); |
1927 | state->textMoveTo(0, 0); | 1927 | state->textMoveTo(0, 0); |
1928 | out->updateTextMat(state); | 1928 | out->updateTextMat(state); |
1929 | out->updateTextPos(state); | 1929 | out->updateTextPos(state); |
1930 | fontChanged = gTrue; | 1930 | fontChanged = gTrue; |
1931 | } | 1931 | } |
1932 | 1932 | ||
1933 | void Gfx::opTextNextLine(Object args[], int numArgs) { | 1933 | void Gfx::opTextNextLine(Object args[], int numArgs) { |
1934 | fouble tx, ty; | 1934 | fouble tx, ty; |
1935 | 1935 | ||
1936 | tx = state->getLineX(); | 1936 | tx = state->getLineX(); |
1937 | ty = state->getLineY() - state->getLeading(); | 1937 | ty = state->getLineY() - state->getLeading(); |
1938 | state->textMoveTo(tx, ty); | 1938 | state->textMoveTo(tx, ty); |
1939 | out->updateTextPos(state); | 1939 | out->updateTextPos(state); |
1940 | } | 1940 | } |
1941 | 1941 | ||
1942 | //------------------------------------------------------------------------ | 1942 | //------------------------------------------------------------------------ |
1943 | // text string operators | 1943 | // text string operators |
1944 | //------------------------------------------------------------------------ | 1944 | //------------------------------------------------------------------------ |
1945 | 1945 | ||
1946 | void Gfx::opShowText(Object args[], int numArgs) { | 1946 | void Gfx::opShowText(Object args[], int numArgs) { |
1947 | if (!state->getFont()) { | 1947 | if (!state->getFont()) { |
1948 | error(getPos(), "No font in show"); | 1948 | error(getPos(), "No font in show"); |
1949 | return; | 1949 | return; |
1950 | } | 1950 | } |
1951 | doShowText(args[0].getString()); | 1951 | doShowText(args[0].getString()); |
1952 | } | 1952 | } |
1953 | 1953 | ||
1954 | void Gfx::opMoveShowText(Object args[], int numArgs) { | 1954 | void Gfx::opMoveShowText(Object args[], int numArgs) { |
1955 | fouble tx, ty; | 1955 | fouble tx, ty; |
1956 | 1956 | ||
1957 | if (!state->getFont()) { | 1957 | if (!state->getFont()) { |
1958 | error(getPos(), "No font in move/show"); | 1958 | error(getPos(), "No font in move/show"); |
1959 | return; | 1959 | return; |
1960 | } | 1960 | } |
1961 | tx = state->getLineX(); | 1961 | tx = state->getLineX(); |
1962 | ty = state->getLineY() - state->getLeading(); | 1962 | ty = state->getLineY() - state->getLeading(); |
1963 | state->textMoveTo(tx, ty); | 1963 | state->textMoveTo(tx, ty); |
1964 | out->updateTextPos(state); | 1964 | out->updateTextPos(state); |
1965 | doShowText(args[0].getString()); | 1965 | doShowText(args[0].getString()); |
1966 | } | 1966 | } |
1967 | 1967 | ||
1968 | void Gfx::opMoveSetShowText(Object args[], int numArgs) { | 1968 | void Gfx::opMoveSetShowText(Object args[], int numArgs) { |
1969 | fouble tx, ty; | 1969 | fouble tx, ty; |
1970 | 1970 | ||
1971 | if (!state->getFont()) { | 1971 | if (!state->getFont()) { |
1972 | error(getPos(), "No font in move/set/show"); | 1972 | error(getPos(), "No font in move/set/show"); |
1973 | return; | 1973 | return; |
1974 | } | 1974 | } |
1975 | state->setWordSpace(args[0].getNum()); | 1975 | state->setWordSpace(args[0].getNum()); |
1976 | state->setCharSpace(args[1].getNum()); | 1976 | state->setCharSpace(args[1].getNum()); |
1977 | tx = state->getLineX(); | 1977 | tx = state->getLineX(); |
1978 | ty = state->getLineY() - state->getLeading(); | 1978 | ty = state->getLineY() - state->getLeading(); |
1979 | state->textMoveTo(tx, ty); | 1979 | state->textMoveTo(tx, ty); |
1980 | out->updateWordSpace(state); | 1980 | out->updateWordSpace(state); |
1981 | out->updateCharSpace(state); | 1981 | out->updateCharSpace(state); |
1982 | out->updateTextPos(state); | 1982 | out->updateTextPos(state); |
1983 | doShowText(args[2].getString()); | 1983 | doShowText(args[2].getString()); |
1984 | } | 1984 | } |
1985 | 1985 | ||
1986 | void Gfx::opShowSpaceText(Object args[], int numArgs) { | 1986 | void Gfx::opShowSpaceText(Object args[], int numArgs) { |
1987 | Array *a; | 1987 | Array *a; |
1988 | Object obj; | 1988 | Object obj; |
1989 | int wMode; | 1989 | int wMode; |
1990 | int i; | 1990 | int i; |
1991 | 1991 | ||
1992 | if (!state->getFont()) { | 1992 | if (!state->getFont()) { |
1993 | error(getPos(), "No font in show/space"); | 1993 | error(getPos(), "No font in show/space"); |
1994 | return; | 1994 | return; |
1995 | } | 1995 | } |
1996 | wMode = state->getFont()->getWMode(); | 1996 | wMode = state->getFont()->getWMode(); |
1997 | a = args[0].getArray(); | 1997 | a = args[0].getArray(); |
1998 | for (i = 0; i < a->getLength(); ++i) { | 1998 | for (i = 0; i < a->getLength(); ++i) { |
1999 | a->get(i, &obj); | 1999 | a->get(i, &obj); |
2000 | if (obj.isNum()) { | 2000 | if (obj.isNum()) { |
2001 | if (wMode) { | 2001 | if (wMode) { |
2002 | state->textShift(0, -obj.getNum() * 0.001 * state->getFontSize()); | 2002 | state->textShift(0, -obj.getNum() * 0.001 * state->getFontSize()); |
2003 | } else { | 2003 | } else { |
2004 | state->textShift(-obj.getNum() * 0.001 * state->getFontSize(), 0); | 2004 | state->textShift(-obj.getNum() * 0.001 * state->getFontSize(), 0); |
2005 | } | 2005 | } |
2006 | out->updateTextShift(state, obj.getNum()); | 2006 | out->updateTextShift(state, obj.getNum()); |
2007 | } else if (obj.isString()) { | 2007 | } else if (obj.isString()) { |
2008 | doShowText(obj.getString()); | 2008 | doShowText(obj.getString()); |
2009 | } else { | 2009 | } else { |
2010 | error(getPos(), "Element of show/space array must be number or string"); | 2010 | error(getPos(), "Element of show/space array must be number or string"); |
2011 | } | 2011 | } |
2012 | obj.free(); | 2012 | obj.free(); |
2013 | } | 2013 | } |
2014 | } | 2014 | } |
2015 | 2015 | ||
2016 | void Gfx::doShowText(GString *s) { | 2016 | void Gfx::doShowText(GString *s) { |
2017 | GfxFont *font; | 2017 | GfxFont *font; |
2018 | int wMode; | 2018 | int wMode; |
2019 | fouble riseX, riseY; | 2019 | fouble riseX, riseY; |
2020 | CharCode code; | 2020 | CharCode code; |
2021 | Unicode u[8]; | 2021 | Unicode u[8]; |
2022 | fouble x, y, dx, dy, dx2, dy2, curX, curY, tdx, tdy; | 2022 | fouble x, y, dx, dy, dx2, dy2, curX, curY, tdx, tdy; |
2023 | fouble originX, originY, tOriginX, tOriginY; | 2023 | fouble originX, originY, tOriginX, tOriginY; |
2024 | fouble oldCTM[6], newCTM[6]; | 2024 | fouble oldCTM[6], newCTM[6]; |
2025 | fouble *mat; | 2025 | fouble *mat; |
2026 | Object charProc; | 2026 | Object charProc; |
2027 | Dict *resDict; | 2027 | Dict *resDict; |
2028 | Parser *oldParser; | 2028 | Parser *oldParser; |
2029 | char *p; | 2029 | char *p; |
2030 | int len, n, uLen, nChars, nSpaces, i; | 2030 | int len, n, uLen, nChars, nSpaces, i; |
2031 | 2031 | ||
2032 | if (fontChanged) { | 2032 | if (fontChanged) { |
2033 | out->updateFont(state); | 2033 | out->updateFont(state); |
2034 | fontChanged = gFalse; | 2034 | fontChanged = gFalse; |
2035 | } | 2035 | } |
2036 | font = state->getFont(); | 2036 | font = state->getFont(); |
2037 | wMode = font->getWMode(); | 2037 | wMode = font->getWMode(); |
2038 | 2038 | ||
2039 | if (out->useDrawChar()) { | 2039 | if (out->useDrawChar()) { |
2040 | out->beginString(state, s); | 2040 | out->beginString(state, s); |
2041 | } | 2041 | } |
2042 | 2042 | ||
2043 | // handle a Type 3 char | 2043 | // handle a Type 3 char |
2044 | if (font->getType() == fontType3 && out->interpretType3Chars()) { | 2044 | if (font->getType() == fontType3 && out->interpretType3Chars()) { |
2045 | mat = state->getCTM(); | 2045 | mat = state->getCTM(); |
2046 | for (i = 0; i < 6; ++i) { | 2046 | for (i = 0; i < 6; ++i) { |
2047 | oldCTM[i] = mat[i]; | 2047 | oldCTM[i] = mat[i]; |
2048 | } | 2048 | } |
2049 | mat = state->getTextMat(); | 2049 | mat = state->getTextMat(); |
2050 | newCTM[0] = mat[0] * oldCTM[0] + mat[1] * oldCTM[2]; | 2050 | newCTM[0] = mat[0] * oldCTM[0] + mat[1] * oldCTM[2]; |
2051 | newCTM[1] = mat[0] * oldCTM[1] + mat[1] * oldCTM[3]; | 2051 | newCTM[1] = mat[0] * oldCTM[1] + mat[1] * oldCTM[3]; |
2052 | newCTM[2] = mat[2] * oldCTM[0] + mat[3] * oldCTM[2]; | 2052 | newCTM[2] = mat[2] * oldCTM[0] + mat[3] * oldCTM[2]; |
2053 | newCTM[3] = mat[2] * oldCTM[1] + mat[3] * oldCTM[3]; | 2053 | newCTM[3] = mat[2] * oldCTM[1] + mat[3] * oldCTM[3]; |
2054 | mat = font->getFontMatrix(); | 2054 | mat = font->getFontMatrix(); |
2055 | newCTM[0] = mat[0] * newCTM[0] + mat[1] * newCTM[2]; | 2055 | newCTM[0] = mat[0] * newCTM[0] + mat[1] * newCTM[2]; |
2056 | newCTM[1] = mat[0] * newCTM[1] + mat[1] * newCTM[3]; | 2056 | newCTM[1] = mat[0] * newCTM[1] + mat[1] * newCTM[3]; |
2057 | newCTM[2] = mat[2] * newCTM[0] + mat[3] * newCTM[2]; | 2057 | newCTM[2] = mat[2] * newCTM[0] + mat[3] * newCTM[2]; |
2058 | newCTM[3] = mat[2] * newCTM[1] + mat[3] * newCTM[3]; | 2058 | newCTM[3] = mat[2] * newCTM[1] + mat[3] * newCTM[3]; |
2059 | newCTM[0] *= state->getFontSize(); | 2059 | newCTM[0] *= state->getFontSize(); |
2060 | newCTM[3] *= state->getFontSize(); | 2060 | newCTM[3] *= state->getFontSize(); |
2061 | newCTM[0] *= state->getHorizScaling(); | 2061 | newCTM[0] *= state->getHorizScaling(); |
2062 | newCTM[2] *= state->getHorizScaling(); | 2062 | newCTM[2] *= state->getHorizScaling(); |
2063 | state->textTransformDelta(0, state->getRise(), &riseX, &riseY); | 2063 | state->textTransformDelta(0, state->getRise(), &riseX, &riseY); |
2064 | curX = state->getCurX(); | 2064 | curX = state->getCurX(); |
2065 | curY = state->getCurY(); | 2065 | curY = state->getCurY(); |
2066 | oldParser = parser; | 2066 | oldParser = parser; |
2067 | p = s->getCString(); | 2067 | p = s->getCString(); |
2068 | len = s->getLength(); | 2068 | len = s->getLength(); |
2069 | while (len > 0) { | 2069 | while (len > 0) { |
2070 | n = font->getNextChar(p, len, &code, | 2070 | n = font->getNextChar(p, len, &code, |
2071 | u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, | 2071 | u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, |
2072 | &dx, &dy, &originX, &originY); | 2072 | &dx, &dy, &originX, &originY); |
2073 | dx = dx * state->getFontSize() + state->getCharSpace(); | 2073 | dx = dx * state->getFontSize() + state->getCharSpace(); |
2074 | if (n == 1 && *p == ' ') { | 2074 | if (n == 1 && *p == ' ') { |
2075 | dx += state->getWordSpace(); | 2075 | dx += state->getWordSpace(); |
2076 | } | 2076 | } |
2077 | dx *= state->getHorizScaling(); | 2077 | dx *= state->getHorizScaling(); |
2078 | dy *= state->getFontSize(); | 2078 | dy *= state->getFontSize(); |
2079 | state->textTransformDelta(dx, dy, &tdx, &tdy); | 2079 | state->textTransformDelta(dx, dy, &tdx, &tdy); |
2080 | state->transform(curX + riseX, curY + riseY, &x, &y); | 2080 | state->transform(curX + riseX, curY + riseY, &x, &y); |
2081 | out->saveState(state); | 2081 | out->saveState(state); |
2082 | state = state->save(); | 2082 | state = state->save(); |
2083 | state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y); | 2083 | state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y); |
2084 | //~ out->updateCTM(???) | 2084 | //~ out->updateCTM(???) |
2085 | if (!out->beginType3Char(state, code, u, uLen)) { | 2085 | if (!out->beginType3Char(state, code, u, uLen)) { |
2086 | ((Gfx8BitFont *)font)->getCharProc(code, &charProc); | 2086 | ((Gfx8BitFont *)font)->getCharProc(code, &charProc); |
2087 | if ((resDict = ((Gfx8BitFont *)font)->getResources())) { | 2087 | if ((resDict = ((Gfx8BitFont *)font)->getResources())) { |
2088 | pushResources(resDict); | 2088 | pushResources(resDict); |
2089 | } | 2089 | } |
2090 | if (charProc.isStream()) { | 2090 | if (charProc.isStream()) { |
2091 | display(&charProc, gFalse); | 2091 | display(&charProc, gFalse); |
2092 | } else { | 2092 | } else { |
2093 | error(getPos(), "Missing or bad Type3 CharProc entry"); | 2093 | error(getPos(), "Missing or bad Type3 CharProc entry"); |
2094 | } | 2094 | } |
2095 | out->endType3Char(state); | 2095 | out->endType3Char(state); |
2096 | if (resDict) { | 2096 | if (resDict) { |
2097 | popResources(); | 2097 | popResources(); |
2098 | } | 2098 | } |
2099 | charProc.free(); | 2099 | charProc.free(); |
2100 | } | 2100 | } |
2101 | state = state->restore(); | 2101 | state = state->restore(); |
2102 | out->restoreState(state); | 2102 | out->restoreState(state); |
2103 | // GfxState::restore() does *not* restore the current position, | 2103 | // GfxState::restore() does *not* restore the current position, |
2104 | // so we track it here with (curX, curY) | 2104 | // so we track it here with (curX, curY) |
2105 | curX += tdx; | 2105 | curX += tdx; |
2106 | curY += tdy; | 2106 | curY += tdy; |
2107 | state->moveTo(curX, curY); | 2107 | state->moveTo(curX, curY); |
2108 | p += n; | 2108 | p += n; |
2109 | len -= n; | 2109 | len -= n; |
2110 | } | 2110 | } |
2111 | parser = oldParser; | 2111 | parser = oldParser; |
2112 | 2112 | ||
2113 | } else if (out->useDrawChar()) { | 2113 | } else if (out->useDrawChar()) { |
2114 | state->textTransformDelta(0, state->getRise(), &riseX, &riseY); | 2114 | state->textTransformDelta(0, state->getRise(), &riseX, &riseY); |
2115 | p = s->getCString(); | 2115 | p = s->getCString(); |
2116 | len = s->getLength(); | 2116 | len = s->getLength(); |
2117 | while (len > 0) { | 2117 | while (len > 0) { |
2118 | n = font->getNextChar(p, len, &code, | 2118 | n = font->getNextChar(p, len, &code, |
2119 | u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, | 2119 | u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, |
2120 | &dx, &dy, &originX, &originY); | 2120 | &dx, &dy, &originX, &originY); |
2121 | if (wMode) { | 2121 | if (wMode) { |
2122 | dx *= state->getFontSize(); | 2122 | dx *= state->getFontSize(); |
2123 | dy = dy * state->getFontSize() + state->getCharSpace(); | 2123 | dy = dy * state->getFontSize() + state->getCharSpace(); |
2124 | if (n == 1 && *p == ' ') { | 2124 | if (n == 1 && *p == ' ') { |
2125 | dy += state->getWordSpace(); | 2125 | dy += state->getWordSpace(); |
2126 | } | 2126 | } |
2127 | } else { | 2127 | } else { |
2128 | dx = dx * state->getFontSize() + state->getCharSpace(); | 2128 | dx = dx * state->getFontSize() + state->getCharSpace(); |
2129 | if (n == 1 && *p == ' ') { | 2129 | if (n == 1 && *p == ' ') { |
2130 | dx += state->getWordSpace(); | 2130 | dx += state->getWordSpace(); |
2131 | } | 2131 | } |
2132 | dx *= state->getHorizScaling(); | 2132 | dx *= state->getHorizScaling(); |
2133 | dy *= state->getFontSize(); | 2133 | dy *= state->getFontSize(); |
2134 | } | 2134 | } |
2135 | state->textTransformDelta(dx, dy, &tdx, &tdy); | 2135 | state->textTransformDelta(dx, dy, &tdx, &tdy); |
2136 | originX *= state->getFontSize(); | 2136 | originX *= state->getFontSize(); |
2137 | originY *= state->getFontSize(); | 2137 | originY *= state->getFontSize(); |
2138 | state->textTransformDelta(originX, originY, &tOriginX, &tOriginY); | 2138 | state->textTransformDelta(originX, originY, &tOriginX, &tOriginY); |
2139 | out->drawChar(state, state->getCurX() + riseX, state->getCurY() + riseY, | 2139 | out->drawChar(state, state->getCurX() + riseX, state->getCurY() + riseY, |
2140 | tdx, tdy, tOriginX, tOriginY, code, u, uLen); | 2140 | tdx, tdy, tOriginX, tOriginY, code, u, uLen); |
2141 | state->shift(tdx, tdy); | 2141 | state->shift(tdx, tdy); |
2142 | p += n; | 2142 | p += n; |
2143 | len -= n; | 2143 | len -= n; |
2144 | } | 2144 | } |
2145 | 2145 | ||
2146 | } else { | 2146 | } else { |
2147 | dx = dy = 0; | 2147 | dx = dy = 0; |
2148 | p = s->getCString(); | 2148 | p = s->getCString(); |
2149 | len = s->getLength(); | 2149 | len = s->getLength(); |
2150 | nChars = nSpaces = 0; | 2150 | nChars = nSpaces = 0; |
2151 | while (len > 0) { | 2151 | while (len > 0) { |
2152 | n = font->getNextChar(p, len, &code, | 2152 | n = font->getNextChar(p, len, &code, |
2153 | u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, | 2153 | u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, |
2154 | &dx2, &dy2, &originX, &originY); | 2154 | &dx2, &dy2, &originX, &originY); |
2155 | dx += dx2; | 2155 | dx += dx2; |
2156 | dy += dy2; | 2156 | dy += dy2; |
2157 | if (n == 1 && *p == ' ') { | 2157 | if (n == 1 && *p == ' ') { |
2158 | ++nSpaces; | 2158 | ++nSpaces; |
2159 | } | 2159 | } |
2160 | ++nChars; | 2160 | ++nChars; |
2161 | p += n; | 2161 | p += n; |
2162 | len -= n; | 2162 | len -= n; |
2163 | } | 2163 | } |
2164 | if (wMode) { | 2164 | if (wMode) { |
2165 | dx *= state->getFontSize(); | 2165 | dx *= state->getFontSize(); |
2166 | dy = dy * state->getFontSize() | 2166 | dy = dy * state->getFontSize() |
2167 | + nChars * state->getCharSpace() | 2167 | + nChars * state->getCharSpace() |
2168 | + nSpaces * state->getWordSpace(); | 2168 | + nSpaces * state->getWordSpace(); |
2169 | } else { | 2169 | } else { |
2170 | dx = dx * state->getFontSize() | 2170 | dx = dx * state->getFontSize() |
2171 | + nChars * state->getCharSpace() | 2171 | + nChars * state->getCharSpace() |
2172 | + nSpaces * state->getWordSpace(); | 2172 | + nSpaces * state->getWordSpace(); |
2173 | dx *= state->getHorizScaling(); | 2173 | dx *= state->getHorizScaling(); |
2174 | dy *= state->getFontSize(); | 2174 | dy *= state->getFontSize(); |
2175 | } | 2175 | } |
2176 | state->textTransformDelta(dx, dy, &tdx, &tdy); | 2176 | state->textTransformDelta(dx, dy, &tdx, &tdy); |
2177 | out->drawString(state, s); | 2177 | out->drawString(state, s); |
2178 | state->shift(tdx, tdy); | 2178 | state->shift(tdx, tdy); |
2179 | } | 2179 | } |
2180 | 2180 | ||
2181 | if (out->useDrawChar()) { | 2181 | if (out->useDrawChar()) { |
2182 | out->endString(state); | 2182 | out->endString(state); |
2183 | } | 2183 | } |
2184 | 2184 | ||
2185 | updateLevel += 10 * s->getLength(); | 2185 | updateLevel += 10 * s->getLength(); |
2186 | } | 2186 | } |
2187 | 2187 | ||
2188 | //------------------------------------------------------------------------ | 2188 | //------------------------------------------------------------------------ |
2189 | // XObject operators | 2189 | // XObject operators |
2190 | //------------------------------------------------------------------------ | 2190 | //------------------------------------------------------------------------ |
2191 | 2191 | ||
2192 | void Gfx::opXObject(Object args[], int numArgs) { | 2192 | void Gfx::opXObject(Object args[], int numArgs) { |
2193 | Object obj1, obj2, obj3, refObj; | 2193 | Object obj1, obj2, obj3, refObj; |
2194 | #if OPI_SUPPORT | 2194 | #if OPI_SUPPORT |
2195 | Object opiDict; | 2195 | Object opiDict; |
2196 | #endif | 2196 | #endif |
2197 | 2197 | ||
2198 | if (!res->lookupXObject(args[0].getName(), &obj1)) { | 2198 | if (!res->lookupXObject(args[0].getName(), &obj1)) { |
2199 | return; | 2199 | return; |
2200 | } | 2200 | } |
2201 | if (!obj1.isStream()) { | 2201 | if (!obj1.isStream()) { |
2202 | error(getPos(), "XObject '%s' is wrong type", args[0].getName()); | 2202 | error(getPos(), "XObject '%s' is wrong type", args[0].getName()); |
2203 | obj1.free(); | 2203 | obj1.free(); |
2204 | return; | 2204 | return; |
2205 | } | 2205 | } |
2206 | #if OPI_SUPPORT | 2206 | #if OPI_SUPPORT |
2207 | obj1.streamGetDict()->lookup("OPI", &opiDict); | 2207 | obj1.streamGetDict()->lookup("OPI", &opiDict); |
2208 | if (opiDict.isDict()) { | 2208 | if (opiDict.isDict()) { |
2209 | out->opiBegin(state, opiDict.getDict()); | 2209 | out->opiBegin(state, opiDict.getDict()); |
2210 | } | 2210 | } |
2211 | #endif | 2211 | #endif |
2212 | obj1.streamGetDict()->lookup("Subtype", &obj2); | 2212 | obj1.streamGetDict()->lookup("Subtype", &obj2); |
2213 | if (obj2.isName("Image")) { | 2213 | if (obj2.isName("Image")) { |
2214 | res->lookupXObjectNF(args[0].getName(), &refObj); | 2214 | res->lookupXObjectNF(args[0].getName(), &refObj); |
2215 | doImage(&refObj, obj1.getStream(), gFalse); | 2215 | doImage(&refObj, obj1.getStream(), gFalse); |
2216 | refObj.free(); | 2216 | refObj.free(); |
2217 | } else if (obj2.isName("Form")) { | 2217 | } else if (obj2.isName("Form")) { |
2218 | doForm(&obj1); | 2218 | doForm(&obj1); |
2219 | } else if (obj2.isName("PS")) { | 2219 | } else if (obj2.isName("PS")) { |
2220 | obj1.streamGetDict()->lookup("Level1", &obj3); | 2220 | obj1.streamGetDict()->lookup("Level1", &obj3); |
2221 | out->psXObject(obj1.getStream(), | 2221 | out->psXObject(obj1.getStream(), |
2222 | obj3.isStream() ? obj3.getStream() : (Stream *)NULL); | 2222 | obj3.isStream() ? obj3.getStream() : (Stream *)NULL); |
2223 | } else if (obj2.isName()) { | 2223 | } else if (obj2.isName()) { |
2224 | error(getPos(), "Unknown XObject subtype '%s'", obj2.getName()); | 2224 | error(getPos(), "Unknown XObject subtype '%s'", obj2.getName()); |
2225 | } else { | 2225 | } else { |
2226 | error(getPos(), "XObject subtype is missing or wrong type"); | 2226 | error(getPos(), "XObject subtype is missing or wrong type"); |
2227 | } | 2227 | } |
2228 | obj2.free(); | 2228 | obj2.free(); |
2229 | #if OPI_SUPPORT | 2229 | #if OPI_SUPPORT |
2230 | if (opiDict.isDict()) { | 2230 | if (opiDict.isDict()) { |
2231 | out->opiEnd(state, opiDict.getDict()); | 2231 | out->opiEnd(state, opiDict.getDict()); |
2232 | } | 2232 | } |
2233 | opiDict.free(); | 2233 | opiDict.free(); |
2234 | #endif | 2234 | #endif |
2235 | obj1.free(); | 2235 | obj1.free(); |
2236 | } | 2236 | } |
2237 | 2237 | ||
2238 | void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { | 2238 | void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { |
2239 | Dict *dict; | 2239 | Dict *dict; |
2240 | int width, height; | 2240 | int width, height; |
2241 | int bits; | 2241 | int bits; |
2242 | GBool mask; | 2242 | GBool mask; |
2243 | GBool invert; | 2243 | GBool invert; |
2244 | GfxColorSpace *colorSpace; | 2244 | GfxColorSpace *colorSpace; |
2245 | GfxImageColorMap *colorMap; | 2245 | GfxImageColorMap *colorMap; |
2246 | Object maskObj; | 2246 | Object maskObj; |
2247 | GBool haveMask; | 2247 | GBool haveMask; |
2248 | int maskColors[2*gfxColorMaxComps]; | 2248 | int maskColors[2*gfxColorMaxComps]; |
2249 | Object obj1, obj2; | 2249 | Object obj1, obj2; |
2250 | int i; | 2250 | int i; |
2251 | 2251 | ||
2252 | // get stream dict | 2252 | // get stream dict |
2253 | dict = str->getDict(); | 2253 | dict = str->getDict(); |
2254 | 2254 | ||
2255 | // get size | 2255 | // get size |
2256 | dict->lookup("Width", &obj1); | 2256 | dict->lookup("Width", &obj1); |
2257 | if (obj1.isNull()) { | 2257 | if (obj1.isNull()) { |
2258 | obj1.free(); | 2258 | obj1.free(); |
2259 | dict->lookup("W", &obj1); | 2259 | dict->lookup("W", &obj1); |
2260 | } | 2260 | } |
2261 | if (!obj1.isInt()) | 2261 | if (!obj1.isInt()) |
2262 | goto err2; | 2262 | goto err2; |
2263 | width = obj1.getInt(); | 2263 | width = obj1.getInt(); |
2264 | obj1.free(); | 2264 | obj1.free(); |
2265 | dict->lookup("Height", &obj1); | 2265 | dict->lookup("Height", &obj1); |
2266 | if (obj1.isNull()) { | 2266 | if (obj1.isNull()) { |
2267 | obj1.free(); | 2267 | obj1.free(); |
2268 | dict->lookup("H", &obj1); | 2268 | dict->lookup("H", &obj1); |
2269 | } | 2269 | } |
2270 | if (!obj1.isInt()) | 2270 | if (!obj1.isInt()) |
2271 | goto err2; | 2271 | goto err2; |
2272 | height = obj1.getInt(); | 2272 | height = obj1.getInt(); |
2273 | obj1.free(); | 2273 | obj1.free(); |
2274 | 2274 | ||
2275 | // image or mask? | 2275 | // image or mask? |
2276 | dict->lookup("ImageMask", &obj1); | 2276 | dict->lookup("ImageMask", &obj1); |
2277 | if (obj1.isNull()) { | 2277 | if (obj1.isNull()) { |
2278 | obj1.free(); | 2278 | obj1.free(); |
2279 | dict->lookup("IM", &obj1); | 2279 | dict->lookup("IM", &obj1); |
2280 | } | 2280 | } |
2281 | mask = gFalse; | 2281 | mask = gFalse; |
2282 | if (obj1.isBool()) | 2282 | if (obj1.isBool()) |
2283 | mask = obj1.getBool(); | 2283 | mask = obj1.getBool(); |
2284 | else if (!obj1.isNull()) | 2284 | else if (!obj1.isNull()) |
2285 | goto err2; | 2285 | goto err2; |
2286 | obj1.free(); | 2286 | obj1.free(); |
2287 | 2287 | ||
2288 | // bit depth | 2288 | // bit depth |
2289 | dict->lookup("BitsPerComponent", &obj1); | 2289 | dict->lookup("BitsPerComponent", &obj1); |
2290 | if (obj1.isNull()) { | 2290 | if (obj1.isNull()) { |
2291 | obj1.free(); | 2291 | obj1.free(); |
2292 | dict->lookup("BPC", &obj1); | 2292 | dict->lookup("BPC", &obj1); |
2293 | } | 2293 | } |
2294 | if (!obj1.isInt()) | 2294 | if (!obj1.isInt()) |
2295 | goto err2; | 2295 | goto err2; |
2296 | bits = obj1.getInt(); | 2296 | bits = obj1.getInt(); |
2297 | obj1.free(); | 2297 | obj1.free(); |
2298 | 2298 | ||
2299 | // display a mask | 2299 | // display a mask |
2300 | if (mask) { | 2300 | if (mask) { |
2301 | 2301 | ||
2302 | // check for inverted mask | 2302 | // check for inverted mask |
2303 | if (bits != 1) | 2303 | if (bits != 1) |
2304 | goto err1; | 2304 | goto err1; |
2305 | invert = gFalse; | 2305 | invert = gFalse; |
2306 | dict->lookup("Decode", &obj1); | 2306 | dict->lookup("Decode", &obj1); |
2307 | if (obj1.isNull()) { | 2307 | if (obj1.isNull()) { |
2308 | obj1.free(); | 2308 | obj1.free(); |
2309 | dict->lookup("D", &obj1); | 2309 | dict->lookup("D", &obj1); |
2310 | } | 2310 | } |
2311 | if (obj1.isArray()) { | 2311 | if (obj1.isArray()) { |
2312 | obj1.arrayGet(0, &obj2); | 2312 | obj1.arrayGet(0, &obj2); |
2313 | if (obj2.isInt() && obj2.getInt() == 1) | 2313 | if (obj2.isInt() && obj2.getInt() == 1) |
2314 | invert = gTrue; | 2314 | invert = gTrue; |
2315 | obj2.free(); | 2315 | obj2.free(); |
2316 | } else if (!obj1.isNull()) { | 2316 | } else if (!obj1.isNull()) { |
2317 | goto err2; | 2317 | goto err2; |
2318 | } | 2318 | } |
2319 | obj1.free(); | 2319 | obj1.free(); |
2320 | 2320 | ||
2321 | // draw it | 2321 | // draw it |
2322 | out->drawImageMask(state, ref, str, width, height, invert, inlineImg); | 2322 | out->drawImageMask(state, ref, str, width, height, invert, inlineImg); |
2323 | 2323 | ||
2324 | } else { | 2324 | } else { |
2325 | 2325 | ||
2326 | // get color space and color map | 2326 | // get color space and color map |
2327 | dict->lookup("ColorSpace", &obj1); | 2327 | dict->lookup("ColorSpace", &obj1); |
2328 | if (obj1.isNull()) { | 2328 | if (obj1.isNull()) { |
2329 | obj1.free(); | 2329 | obj1.free(); |
2330 | dict->lookup("CS", &obj1); | 2330 | dict->lookup("CS", &obj1); |
2331 | } | 2331 | } |
2332 | if (obj1.isName()) { | 2332 | if (obj1.isName()) { |
2333 | res->lookupColorSpace(obj1.getName(), &obj2); | 2333 | res->lookupColorSpace(obj1.getName(), &obj2); |
2334 | if (!obj2.isNull()) { | 2334 | if (!obj2.isNull()) { |
2335 | obj1.free(); | 2335 | obj1.free(); |
2336 | obj1 = obj2; | 2336 | obj1 = obj2; |
2337 | } else { | 2337 | } else { |
2338 | obj2.free(); | 2338 | obj2.free(); |
2339 | } | 2339 | } |
2340 | } | 2340 | } |
2341 | colorSpace = GfxColorSpace::parse(&obj1); | 2341 | colorSpace = GfxColorSpace::parse(&obj1); |
2342 | obj1.free(); | 2342 | obj1.free(); |
2343 | if (!colorSpace) { | 2343 | if (!colorSpace) { |
2344 | goto err1; | 2344 | goto err1; |
2345 | } | 2345 | } |
2346 | dict->lookup("Decode", &obj1); | 2346 | dict->lookup("Decode", &obj1); |
2347 | if (obj1.isNull()) { | 2347 | if (obj1.isNull()) { |
2348 | obj1.free(); | 2348 | obj1.free(); |
2349 | dict->lookup("D", &obj1); | 2349 | dict->lookup("D", &obj1); |
2350 | } | 2350 | } |
2351 | colorMap = new GfxImageColorMap(bits, &obj1, colorSpace); | 2351 | colorMap = new GfxImageColorMap(bits, &obj1, colorSpace); |
2352 | obj1.free(); | 2352 | obj1.free(); |
2353 | if (!colorMap->isOk()) { | 2353 | if (!colorMap->isOk()) { |
2354 | delete colorMap; | 2354 | delete colorMap; |
2355 | goto err1; | 2355 | goto err1; |
2356 | } | 2356 | } |
2357 | 2357 | ||
2358 | // get the mask | 2358 | // get the mask |
2359 | haveMask = gFalse; | 2359 | haveMask = gFalse; |
2360 | dict->lookup("Mask", &maskObj); | 2360 | dict->lookup("Mask", &maskObj); |
2361 | if (maskObj.isArray()) { | 2361 | if (maskObj.isArray()) { |
2362 | for (i = 0; i < maskObj.arrayGetLength(); ++i) { | 2362 | for (i = 0; i < maskObj.arrayGetLength(); ++i) { |
2363 | maskObj.arrayGet(i, &obj1); | 2363 | maskObj.arrayGet(i, &obj1); |
2364 | maskColors[i] = obj1.getInt(); | 2364 | maskColors[i] = obj1.getInt(); |
2365 | obj1.free(); | 2365 | obj1.free(); |
2366 | } | 2366 | } |
2367 | haveMask = gTrue; | 2367 | haveMask = gTrue; |
2368 | } | 2368 | } |
2369 | 2369 | ||
2370 | // draw it | 2370 | // draw it |
2371 | out->drawImage(state, ref, str, width, height, colorMap, | 2371 | out->drawImage(state, ref, str, width, height, colorMap, |
2372 | haveMask ? maskColors : (int *)NULL, inlineImg); | 2372 | haveMask ? maskColors : (int *)NULL, inlineImg); |
2373 | delete colorMap; | 2373 | delete colorMap; |
2374 | 2374 | ||
2375 | maskObj.free(); | 2375 | maskObj.free(); |
2376 | } | 2376 | } |
2377 | 2377 | ||
2378 | if ((i = width * height) > 1000) { | 2378 | if ((i = width * height) > 1000) { |
2379 | i = 1000; | 2379 | i = 1000; |
2380 | } | 2380 | } |
2381 | updateLevel += i; | 2381 | updateLevel += i; |
2382 | 2382 | ||
2383 | return; | 2383 | return; |
2384 | 2384 | ||
2385 | err2: | 2385 | err2: |
2386 | obj1.free(); | 2386 | obj1.free(); |
2387 | err1: | 2387 | err1: |
2388 | error(getPos(), "Bad image parameters"); | 2388 | error(getPos(), "Bad image parameters"); |
2389 | } | 2389 | } |
2390 | 2390 | ||
2391 | void Gfx::doForm(Object *str) { | 2391 | void Gfx::doForm(Object *str) { |
2392 | Dict *dict; | 2392 | Dict *dict; |
2393 | Object matrixObj, bboxObj; | 2393 | Object matrixObj, bboxObj; |
2394 | fouble m[6], bbox[6]; | 2394 | fouble m[6], bbox[6]; |
2395 | Object resObj; | 2395 | Object resObj; |
2396 | Dict *resDict; | 2396 | Dict *resDict; |
2397 | Object obj1; | 2397 | Object obj1; |
2398 | int i; | 2398 | int i; |
2399 | 2399 | ||
2400 | // get stream dict | 2400 | // get stream dict |
2401 | dict = str->streamGetDict(); | 2401 | dict = str->streamGetDict(); |
2402 | 2402 | ||
2403 | // check form type | 2403 | // check form type |
2404 | dict->lookup("FormType", &obj1); | 2404 | dict->lookup("FormType", &obj1); |
2405 | if (!(obj1.isInt() && obj1.getInt() == 1)) { | 2405 | if (!(obj1.isInt() && obj1.getInt() == 1)) { |
2406 | error(getPos(), "Unknown form type"); | 2406 | error(getPos(), "Unknown form type"); |
2407 | } | 2407 | } |
2408 | obj1.free(); | 2408 | obj1.free(); |
2409 | 2409 | ||
2410 | // get bounding box | 2410 | // get bounding box |
2411 | dict->lookup("BBox", &bboxObj); | 2411 | dict->lookup("BBox", &bboxObj); |
2412 | if (!bboxObj.isArray()) { | 2412 | if (!bboxObj.isArray()) { |
2413 | matrixObj.free(); | 2413 | matrixObj.free(); |
2414 | bboxObj.free(); | 2414 | bboxObj.free(); |
2415 | error(getPos(), "Bad form bounding box"); | 2415 | error(getPos(), "Bad form bounding box"); |
2416 | return; | 2416 | return; |
2417 | } | 2417 | } |
2418 | for (i = 0; i < 4; ++i) { | 2418 | for (i = 0; i < 4; ++i) { |
2419 | bboxObj.arrayGet(i, &obj1); | 2419 | bboxObj.arrayGet(i, &obj1); |
2420 | bbox[i] = obj1.getNum(); | 2420 | bbox[i] = obj1.getNum(); |
2421 | obj1.free(); | 2421 | obj1.free(); |
2422 | } | 2422 | } |
2423 | bboxObj.free(); | 2423 | bboxObj.free(); |
2424 | 2424 | ||
2425 | // get matrix | 2425 | // get matrix |
2426 | dict->lookup("Matrix", &matrixObj); | 2426 | dict->lookup("Matrix", &matrixObj); |
2427 | if (matrixObj.isArray()) { | 2427 | if (matrixObj.isArray()) { |
2428 | for (i = 0; i < 6; ++i) { | 2428 | for (i = 0; i < 6; ++i) { |
2429 | matrixObj.arrayGet(i, &obj1); | 2429 | matrixObj.arrayGet(i, &obj1); |
2430 | m[i] = obj1.getNum(); | 2430 | m[i] = obj1.getNum(); |
2431 | obj1.free(); | 2431 | obj1.free(); |
2432 | } | 2432 | } |
2433 | } else { | 2433 | } else { |
2434 | m[0] = 1; m[1] = 0; | 2434 | m[0] = 1; m[1] = 0; |
2435 | m[2] = 0; m[3] = 1; | 2435 | m[2] = 0; m[3] = 1; |
2436 | m[4] = 0; m[5] = 0; | 2436 | m[4] = 0; m[5] = 0; |
2437 | } | 2437 | } |
2438 | matrixObj.free(); | 2438 | matrixObj.free(); |
2439 | 2439 | ||
2440 | // get resources | 2440 | // get resources |
2441 | dict->lookup("Resources", &resObj); | 2441 | dict->lookup("Resources", &resObj); |
2442 | resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL; | 2442 | resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL; |
2443 | 2443 | ||
2444 | // draw it | 2444 | // draw it |
2445 | doForm1(str, resDict, m, bbox); | 2445 | doForm1(str, resDict, m, bbox); |
2446 | 2446 | ||
2447 | resObj.free(); | 2447 | resObj.free(); |
2448 | } | 2448 | } |
2449 | 2449 | ||
2450 | void Gfx::doAnnot(Object *str, fouble xMin, fouble yMin, | 2450 | void Gfx::doAnnot(Object *str, fouble xMin, fouble yMin, |
2451 | fouble xMax, fouble yMax) { | 2451 | fouble xMax, fouble yMax) { |
2452 | Dict *dict, *resDict; | 2452 | Dict *dict, *resDict; |
2453 | Object matrixObj, bboxObj, resObj; | 2453 | Object matrixObj, bboxObj, resObj; |
2454 | Object obj1; | 2454 | Object obj1; |
2455 | fouble m[6], bbox[6], ictm[6]; | 2455 | fouble m[6], bbox[6], ictm[6]; |
2456 | fouble *ctm; | 2456 | fouble *ctm; |
2457 | fouble formX0, formY0, formX1, formY1; | 2457 | fouble formX0, formY0, formX1, formY1; |
2458 | fouble annotX0, annotY0, annotX1, annotY1; | 2458 | fouble annotX0, annotY0, annotX1, annotY1; |
2459 | fouble det, x, y, sx, sy; | 2459 | fouble det, x, y, sx, sy; |
2460 | int i; | 2460 | int i; |
2461 | 2461 | ||
2462 | // get stream dict | 2462 | // get stream dict |
2463 | dict = str->streamGetDict(); | 2463 | dict = str->streamGetDict(); |
2464 | 2464 | ||
2465 | // get the form bounding box | 2465 | // get the form bounding box |
2466 | dict->lookup("BBox", &bboxObj); | 2466 | dict->lookup("BBox", &bboxObj); |
2467 | if (!bboxObj.isArray()) { | 2467 | if (!bboxObj.isArray()) { |
2468 | bboxObj.free(); | 2468 | bboxObj.free(); |
2469 | error(getPos(), "Bad form bounding box"); | 2469 | error(getPos(), "Bad form bounding box"); |
2470 | return; | 2470 | return; |
2471 | } | 2471 | } |
2472 | for (i = 0; i < 4; ++i) { | 2472 | for (i = 0; i < 4; ++i) { |
2473 | bboxObj.arrayGet(i, &obj1); | 2473 | bboxObj.arrayGet(i, &obj1); |
2474 | bbox[i] = obj1.getNum(); | 2474 | bbox[i] = obj1.getNum(); |
2475 | obj1.free(); | 2475 | obj1.free(); |
2476 | } | 2476 | } |
2477 | bboxObj.free(); | 2477 | bboxObj.free(); |
2478 | 2478 | ||
2479 | // get the form matrix | 2479 | // get the form matrix |
2480 | dict->lookup("Matrix", &matrixObj); | 2480 | dict->lookup("Matrix", &matrixObj); |
2481 | if (matrixObj.isArray()) { | 2481 | if (matrixObj.isArray()) { |
2482 | for (i = 0; i < 6; ++i) { | 2482 | for (i = 0; i < 6; ++i) { |
2483 | matrixObj.arrayGet(i, &obj1); | 2483 | matrixObj.arrayGet(i, &obj1); |
2484 | m[i] = obj1.getNum(); | 2484 | m[i] = obj1.getNum(); |
2485 | obj1.free(); | 2485 | obj1.free(); |
2486 | } | 2486 | } |
2487 | } else { | 2487 | } else { |
2488 | m[0] = 1; m[1] = 0; | 2488 | m[0] = 1; m[1] = 0; |
2489 | m[2] = 0; m[3] = 1; | 2489 | m[2] = 0; m[3] = 1; |
2490 | m[4] = 0; m[5] = 0; | 2490 | m[4] = 0; m[5] = 0; |
2491 | } | 2491 | } |
2492 | matrixObj.free(); | 2492 | matrixObj.free(); |
2493 | 2493 | ||
2494 | // transform the form bbox from form space to user space | 2494 | // transform the form bbox from form space to user space |
2495 | formX0 = bbox[0] * m[0] + bbox[1] * m[2] + m[4]; | 2495 | formX0 = bbox[0] * m[0] + bbox[1] * m[2] + m[4]; |
2496 | formY0 = bbox[0] * m[1] + bbox[1] * m[3] + m[5]; | 2496 | formY0 = bbox[0] * m[1] + bbox[1] * m[3] + m[5]; |
2497 | formX1 = bbox[2] * m[0] + bbox[3] * m[2] + m[4]; | 2497 | formX1 = bbox[2] * m[0] + bbox[3] * m[2] + m[4]; |
2498 | formY1 = bbox[2] * m[1] + bbox[3] * m[3] + m[5]; | 2498 | formY1 = bbox[2] * m[1] + bbox[3] * m[3] + m[5]; |
2499 | 2499 | ||
2500 | // transform the annotation bbox from default user space to user | 2500 | // transform the annotation bbox from default user space to user |
2501 | // space: (bbox * baseMatrix) * iCTM | 2501 | // space: (bbox * baseMatrix) * iCTM |
2502 | ctm = state->getCTM(); | 2502 | ctm = state->getCTM(); |
2503 | det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]); | 2503 | det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]); |
2504 | ictm[0] = ctm[3] * det; | 2504 | ictm[0] = ctm[3] * det; |
2505 | ictm[1] = -ctm[1] * det; | 2505 | ictm[1] = -ctm[1] * det; |
2506 | ictm[2] = -ctm[2] * det; | 2506 | ictm[2] = -ctm[2] * det; |
2507 | ictm[3] = ctm[0] * det; | 2507 | ictm[3] = ctm[0] * det; |
2508 | ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det; | 2508 | ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det; |
2509 | ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det; | 2509 | ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det; |
2510 | x = baseMatrix[0] * xMin + baseMatrix[2] * yMin + baseMatrix[4]; | 2510 | x = baseMatrix[0] * xMin + baseMatrix[2] * yMin + baseMatrix[4]; |
2511 | y = baseMatrix[1] * xMin + baseMatrix[3] * yMin + baseMatrix[5]; | 2511 | y = baseMatrix[1] * xMin + baseMatrix[3] * yMin + baseMatrix[5]; |
2512 | annotX0 = ictm[0] * x + ictm[2] * y + ictm[4]; | 2512 | annotX0 = ictm[0] * x + ictm[2] * y + ictm[4]; |
2513 | annotY0 = ictm[1] * x + ictm[3] * y + ictm[5]; | 2513 | annotY0 = ictm[1] * x + ictm[3] * y + ictm[5]; |
2514 | x = baseMatrix[0] * xMax + baseMatrix[2] * yMax + baseMatrix[4]; | 2514 | x = baseMatrix[0] * xMax + baseMatrix[2] * yMax + baseMatrix[4]; |
2515 | y = baseMatrix[1] * xMax + baseMatrix[3] * yMax + baseMatrix[5]; | 2515 | y = baseMatrix[1] * xMax + baseMatrix[3] * yMax + baseMatrix[5]; |
2516 | annotX1 = ictm[0] * x + ictm[2] * y + ictm[4]; | 2516 | annotX1 = ictm[0] * x + ictm[2] * y + ictm[4]; |
2517 | annotY1 = ictm[1] * x + ictm[3] * y + ictm[5]; | 2517 | annotY1 = ictm[1] * x + ictm[3] * y + ictm[5]; |
2518 | 2518 | ||
2519 | // swap min/max coords | 2519 | // swap min/max coords |
2520 | if (formX0 > formX1) { | 2520 | if (formX0 > formX1) { |
2521 | x = formX0; formX0 = formX1; formX1 = x; | 2521 | x = formX0; formX0 = formX1; formX1 = x; |
2522 | } | 2522 | } |
2523 | if (formY0 > formY1) { | 2523 | if (formY0 > formY1) { |
2524 | y = formY0; formY0 = formY1; formY1 = y; | 2524 | y = formY0; formY0 = formY1; formY1 = y; |
2525 | } | 2525 | } |
2526 | if (annotX0 > annotX1) { | 2526 | if (annotX0 > annotX1) { |
2527 | x = annotX0; annotX0 = annotX1; annotX1 = x; | 2527 | x = annotX0; annotX0 = annotX1; annotX1 = x; |
2528 | } | 2528 | } |
2529 | if (annotY0 > annotY1) { | 2529 | if (annotY0 > annotY1) { |
2530 | y = annotY0; annotY0 = annotY1; annotY1 = y; | 2530 | y = annotY0; annotY0 = annotY1; annotY1 = y; |
2531 | } | 2531 | } |
2532 | 2532 | ||
2533 | // scale the form to fit the annotation bbox | 2533 | // scale the form to fit the annotation bbox |
2534 | if (formX1 == formX0) { | 2534 | if (formX1 == formX0) { |
2535 | // this shouldn't happen | 2535 | // this shouldn't happen |
2536 | sx = 1; | 2536 | sx = 1; |
2537 | } else { | 2537 | } else { |
2538 | sx = (annotX1 - annotX0) / (formX1 - formX0); | 2538 | sx = (annotX1 - annotX0) / (formX1 - formX0); |
2539 | } | 2539 | } |
2540 | if (formY1 == formY0) { | 2540 | if (formY1 == formY0) { |
2541 | // this shouldn't happen | 2541 | // this shouldn't happen |
2542 | sy = 1; | 2542 | sy = 1; |
2543 | } else { | 2543 | } else { |
2544 | sy = (annotY1 - annotY0) / (formY1 - formY0); | 2544 | sy = (annotY1 - annotY0) / (formY1 - formY0); |
2545 | } | 2545 | } |
2546 | m[0] *= sx; | 2546 | m[0] *= sx; |
2547 | m[2] *= sx; | 2547 | m[2] *= sx; |
2548 | m[4] = (m[4] - formX0) * sx + annotX0; | 2548 | m[4] = (m[4] - formX0) * sx + annotX0; |
2549 | m[1] *= sy; | 2549 | m[1] *= sy; |
2550 | m[3] *= sy; | 2550 | m[3] *= sy; |
2551 | m[5] = (m[5] - formY0) * sy + annotY0; | 2551 | m[5] = (m[5] - formY0) * sy + annotY0; |
2552 | 2552 | ||
2553 | // get resources | 2553 | // get resources |
2554 | dict->lookup("Resources", &resObj); | 2554 | dict->lookup("Resources", &resObj); |
2555 | resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL; | 2555 | resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL; |
2556 | 2556 | ||
2557 | // draw it | 2557 | // draw it |
2558 | doForm1(str, resDict, m, bbox); | 2558 | doForm1(str, resDict, m, bbox); |
2559 | 2559 | ||
2560 | resObj.free(); | 2560 | resObj.free(); |
2561 | bboxObj.free(); | 2561 | bboxObj.free(); |
2562 | } | 2562 | } |
2563 | 2563 | ||
2564 | void Gfx::doForm1(Object *str, Dict *resDict, fouble *matrix, fouble *bbox) { | 2564 | void Gfx::doForm1(Object *str, Dict *resDict, fouble *matrix, fouble *bbox) { |
2565 | Parser *oldParser; | 2565 | Parser *oldParser; |
2566 | fouble oldBaseMatrix[6]; | 2566 | fouble oldBaseMatrix[6]; |
2567 | int i; | 2567 | int i; |
2568 | 2568 | ||
2569 | // push new resources on stack | 2569 | // push new resources on stack |
2570 | pushResources(resDict); | 2570 | pushResources(resDict); |
2571 | 2571 | ||
2572 | // save current graphics state | 2572 | // save current graphics state |
2573 | out->saveState(state); | 2573 | out->saveState(state); |
2574 | state = state->save(); | 2574 | state = state->save(); |
2575 | 2575 | ||
2576 | // save current parser | 2576 | // save current parser |
2577 | oldParser = parser; | 2577 | oldParser = parser; |
2578 | 2578 | ||
2579 | // set form transformation matrix | 2579 | // set form transformation matrix |
2580 | state->concatCTM(matrix[0], matrix[1], matrix[2], | 2580 | state->concatCTM(matrix[0], matrix[1], matrix[2], |
2581 | matrix[3], matrix[4], matrix[5]); | 2581 | matrix[3], matrix[4], matrix[5]); |
2582 | out->updateCTM(state, matrix[0], matrix[1], matrix[2], | 2582 | out->updateCTM(state, matrix[0], matrix[1], matrix[2], |
2583 | matrix[3], matrix[4], matrix[5]); | 2583 | matrix[3], matrix[4], matrix[5]); |
2584 | 2584 | ||
2585 | // set new base matrix | 2585 | // set new base matrix |
2586 | for (i = 0; i < 6; ++i) { | 2586 | for (i = 0; i < 6; ++i) { |
2587 | oldBaseMatrix[i] = baseMatrix[i]; | 2587 | oldBaseMatrix[i] = baseMatrix[i]; |
2588 | baseMatrix[i] = state->getCTM()[i]; | 2588 | baseMatrix[i] = state->getCTM()[i]; |
2589 | } | 2589 | } |
2590 | 2590 | ||
2591 | // set form bounding box | 2591 | // set form bounding box |
2592 | state->moveTo(bbox[0], bbox[1]); | 2592 | state->moveTo(bbox[0], bbox[1]); |
2593 | state->lineTo(bbox[2], bbox[1]); | 2593 | state->lineTo(bbox[2], bbox[1]); |
2594 | state->lineTo(bbox[2], bbox[3]); | 2594 | state->lineTo(bbox[2], bbox[3]); |
2595 | state->lineTo(bbox[0], bbox[3]); | 2595 | state->lineTo(bbox[0], bbox[3]); |
2596 | state->closePath(); | 2596 | state->closePath(); |
2597 | state->clip(); | 2597 | state->clip(); |
2598 | out->clip(state); | 2598 | out->clip(state); |
2599 | state->clearPath(); | 2599 | state->clearPath(); |
2600 | 2600 | ||
2601 | // draw the form | 2601 | // draw the form |
2602 | display(str, gFalse); | 2602 | display(str, gFalse); |
2603 | 2603 | ||
2604 | // restore base matrix | 2604 | // restore base matrix |
2605 | for (i = 0; i < 6; ++i) { | 2605 | for (i = 0; i < 6; ++i) { |
2606 | baseMatrix[i] = oldBaseMatrix[i]; | 2606 | baseMatrix[i] = oldBaseMatrix[i]; |
2607 | } | 2607 | } |
2608 | 2608 | ||
2609 | // restore parser | 2609 | // restore parser |
2610 | parser = oldParser; | 2610 | parser = oldParser; |
2611 | 2611 | ||
2612 | // restore graphics state | 2612 | // restore graphics state |
2613 | state = state->restore(); | 2613 | state = state->restore(); |
2614 | out->restoreState(state); | 2614 | out->restoreState(state); |
2615 | 2615 | ||
2616 | // pop resource stack | 2616 | // pop resource stack |
2617 | popResources(); | 2617 | popResources(); |
2618 | 2618 | ||
2619 | return; | 2619 | return; |
2620 | } | 2620 | } |
2621 | 2621 | ||
2622 | void Gfx::pushResources(Dict *resDict) { | 2622 | void Gfx::pushResources(Dict *resDict) { |
2623 | res = new GfxResources(xref, resDict, res); | 2623 | res = new GfxResources(xref, resDict, res); |
2624 | } | 2624 | } |
2625 | 2625 | ||
2626 | void Gfx::popResources() { | 2626 | void Gfx::popResources() { |
2627 | GfxResources *resPtr; | 2627 | GfxResources *resPtr; |
2628 | 2628 | ||
2629 | resPtr = res->getNext(); | 2629 | resPtr = res->getNext(); |
2630 | delete res; | 2630 | delete res; |
2631 | res = resPtr; | 2631 | res = resPtr; |
2632 | } | 2632 | } |
2633 | 2633 | ||
2634 | //------------------------------------------------------------------------ | 2634 | //------------------------------------------------------------------------ |
2635 | // in-line image operators | 2635 | // in-line image operators |
2636 | //------------------------------------------------------------------------ | 2636 | //------------------------------------------------------------------------ |
2637 | 2637 | ||
2638 | void Gfx::opBeginImage(Object args[], int numArgs) { | 2638 | void Gfx::opBeginImage(Object args[], int numArgs) { |
2639 | Stream *str; | 2639 | Stream *str; |
2640 | int c1, c2; | 2640 | int c1, c2; |
2641 | 2641 | ||
2642 | // build dict/stream | 2642 | // build dict/stream |
2643 | str = buildImageStream(); | 2643 | str = buildImageStream(); |
2644 | 2644 | ||
2645 | // display the image | 2645 | // display the image |
2646 | if (str) { | 2646 | if (str) { |
2647 | doImage(NULL, str, gTrue); | 2647 | doImage(NULL, str, gTrue); |
2648 | 2648 | ||
2649 | // skip 'EI' tag | 2649 | // skip 'EI' tag |
2650 | c1 = str->getBaseStream()->getChar(); | 2650 | c1 = str->getBaseStream()->getChar(); |
2651 | c2 = str->getBaseStream()->getChar(); | 2651 | c2 = str->getBaseStream()->getChar(); |
2652 | while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) { | 2652 | while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) { |
2653 | c1 = c2; | 2653 | c1 = c2; |
2654 | c2 = str->getBaseStream()->getChar(); | 2654 | c2 = str->getBaseStream()->getChar(); |
2655 | } | 2655 | } |
2656 | delete str; | 2656 | delete str; |
2657 | } | 2657 | } |
2658 | } | 2658 | } |
2659 | 2659 | ||
2660 | Stream *Gfx::buildImageStream() { | 2660 | Stream *Gfx::buildImageStream() { |
2661 | Object dict; | 2661 | Object dict; |
2662 | Object obj; | 2662 | Object obj; |
2663 | char *key; | 2663 | char *key; |
2664 | Stream *str; | 2664 | Stream *str; |
2665 | 2665 | ||
2666 | // build dictionary | 2666 | // build dictionary |
2667 | dict.initDict(xref); | 2667 | dict.initDict(xref); |
2668 | parser->getObj(&obj); | 2668 | parser->getObj(&obj); |
2669 | while (!obj.isCmd("ID") && !obj.isEOF()) { | 2669 | while (!obj.isCmd("ID") && !obj.isEOF()) { |
2670 | if (!obj.isName()) { | 2670 | if (!obj.isName()) { |
2671 | error(getPos(), "Inline image dictionary key must be a name object"); | 2671 | error(getPos(), "Inline image dictionary key must be a name object"); |
2672 | obj.free(); | 2672 | obj.free(); |
2673 | } else { | 2673 | } else { |
2674 | key = copyString(obj.getName()); | 2674 | key = copyString(obj.getName()); |
2675 | obj.free(); | 2675 | obj.free(); |
2676 | parser->getObj(&obj); | 2676 | parser->getObj(&obj); |
2677 | if (obj.isEOF() || obj.isError()) { | 2677 | if (obj.isEOF() || obj.isError()) { |
2678 | gfree(key); | 2678 | gfree(key); |
2679 | break; | 2679 | break; |
2680 | } | 2680 | } |
2681 | dict.dictAdd(key, &obj); | 2681 | dict.dictAdd(key, &obj); |
2682 | } | 2682 | } |
2683 | parser->getObj(&obj); | 2683 | parser->getObj(&obj); |
2684 | } | 2684 | } |
2685 | if (obj.isEOF()) { | 2685 | if (obj.isEOF()) { |
2686 | error(getPos(), "End of file in inline image"); | 2686 | error(getPos(), "End of file in inline image"); |
2687 | obj.free(); | 2687 | obj.free(); |
2688 | dict.free(); | 2688 | dict.free(); |
2689 | return NULL; | 2689 | return NULL; |
2690 | } | 2690 | } |
2691 | obj.free(); | 2691 | obj.free(); |
2692 | 2692 | ||
2693 | // make stream | 2693 | // make stream |
2694 | str = new EmbedStream(parser->getStream(), &dict); | 2694 | str = new EmbedStream(parser->getStream(), &dict); |
2695 | str = str->addFilters(&dict); | 2695 | str = str->addFilters(&dict); |
2696 | 2696 | ||
2697 | return str; | 2697 | return str; |
2698 | } | 2698 | } |
2699 | 2699 | ||
2700 | void Gfx::opImageData(Object args[], int numArgs) { | 2700 | void Gfx::opImageData(Object args[], int numArgs) { |
2701 | error(getPos(), "Internal: got 'ID' operator"); | 2701 | error(getPos(), "Internal: got 'ID' operator"); |
2702 | } | 2702 | } |
2703 | 2703 | ||
2704 | void Gfx::opEndImage(Object args[], int numArgs) { | 2704 | void Gfx::opEndImage(Object args[], int numArgs) { |
2705 | error(getPos(), "Internal: got 'EI' operator"); | 2705 | error(getPos(), "Internal: got 'EI' operator"); |
2706 | } | 2706 | } |
2707 | 2707 | ||
2708 | //------------------------------------------------------------------------ | 2708 | //------------------------------------------------------------------------ |
2709 | // type 3 font operators | 2709 | // type 3 font operators |
2710 | //------------------------------------------------------------------------ | 2710 | //------------------------------------------------------------------------ |
2711 | 2711 | ||
2712 | void Gfx::opSetCharWidth(Object args[], int numArgs) { | 2712 | void Gfx::opSetCharWidth(Object args[], int numArgs) { |
2713 | out->type3D0(state, args[0].getNum(), args[1].getNum()); | 2713 | out->type3D0(state, args[0].getNum(), args[1].getNum()); |
2714 | } | 2714 | } |
2715 | 2715 | ||
2716 | void Gfx::opSetCacheDevice(Object args[], int numArgs) { | 2716 | void Gfx::opSetCacheDevice(Object args[], int numArgs) { |
2717 | out->type3D1(state, args[0].getNum(), args[1].getNum(), | 2717 | out->type3D1(state, args[0].getNum(), args[1].getNum(), |
2718 | args[2].getNum(), args[3].getNum(), | 2718 | args[2].getNum(), args[3].getNum(), |
2719 | args[4].getNum(), args[5].getNum()); | 2719 | args[4].getNum(), args[5].getNum()); |
2720 | } | 2720 | } |
2721 | 2721 | ||
2722 | //------------------------------------------------------------------------ | 2722 | //------------------------------------------------------------------------ |
2723 | // compatibility operators | 2723 | // compatibility operators |
2724 | //------------------------------------------------------------------------ | 2724 | //------------------------------------------------------------------------ |
2725 | 2725 | ||
2726 | void Gfx::opBeginIgnoreUndef(Object args[], int numArgs) { | 2726 | void Gfx::opBeginIgnoreUndef(Object args[], int numArgs) { |
2727 | ++ignoreUndef; | 2727 | ++ignoreUndef; |
2728 | } | 2728 | } |
2729 | 2729 | ||
2730 | void Gfx::opEndIgnoreUndef(Object args[], int numArgs) { | 2730 | void Gfx::opEndIgnoreUndef(Object args[], int numArgs) { |
2731 | if (ignoreUndef > 0) | 2731 | if (ignoreUndef > 0) |
2732 | --ignoreUndef; | 2732 | --ignoreUndef; |
2733 | } | 2733 | } |
2734 | 2734 | ||
2735 | //------------------------------------------------------------------------ | 2735 | //------------------------------------------------------------------------ |
2736 | // marked content operators | 2736 | // marked content operators |
2737 | //------------------------------------------------------------------------ | 2737 | //------------------------------------------------------------------------ |
2738 | 2738 | ||
2739 | void Gfx::opBeginMarkedContent(Object args[], int numArgs) { | 2739 | void Gfx::opBeginMarkedContent(Object args[], int numArgs) { |
2740 | if (printCommands) { | 2740 | if (printCommands) { |
2741 | printf(" marked content: %s ", args[0].getName()); | 2741 | printf(" marked content: %s ", args[0].getName()); |
2742 | if (numArgs == 2) | 2742 | if (numArgs == 2) |
2743 | args[2].print(stdout); | 2743 | args[2].print(stdout); |
2744 | printf("\n"); | 2744 | printf("\n"); |
2745 | fflush(stdout); | 2745 | fflush(stdout); |
2746 | } | 2746 | } |
2747 | } | 2747 | } |
2748 | 2748 | ||
2749 | void Gfx::opEndMarkedContent(Object args[], int numArgs) { | 2749 | void Gfx::opEndMarkedContent(Object args[], int numArgs) { |
2750 | } | 2750 | } |
2751 | 2751 | ||
2752 | void Gfx::opMarkPoint(Object args[], int numArgs) { | 2752 | void Gfx::opMarkPoint(Object args[], int numArgs) { |
2753 | if (printCommands) { | 2753 | if (printCommands) { |
2754 | printf(" mark point: %s ", args[0].getName()); | 2754 | printf(" mark point: %s ", args[0].getName()); |
2755 | if (numArgs == 2) | 2755 | if (numArgs == 2) |
2756 | args[2].print(stdout); | 2756 | args[2].print(stdout); |
2757 | printf("\n"); | 2757 | printf("\n"); |
2758 | fflush(stdout); | 2758 | fflush(stdout); |
2759 | } | 2759 | } |
2760 | } | 2760 | } |
diff --git a/noncore/unsupported/qpdf/xpdf/Object.cc b/noncore/unsupported/qpdf/xpdf/Object.cc index 6d92c6a..77f1317 100644 --- a/noncore/unsupported/qpdf/xpdf/Object.cc +++ b/noncore/unsupported/qpdf/xpdf/Object.cc | |||
@@ -1,223 +1,223 @@ | |||
1 | //======================================================================== | 1 | //======================================================================== |
2 | // | 2 | // |
3 | // Object.cc | 3 | // Object.cc |
4 | // | 4 | // |
5 | // Copyright 1996-2002 Glyph & Cog, LLC | 5 | // Copyright 1996-2002 Glyph & Cog, LLC |
6 | // | 6 | // |
7 | //======================================================================== | 7 | //======================================================================== |
8 | 8 | ||
9 | #ifdef __GNUC__ | 9 | #ifdef __GNUC__ |
10 | #pragma implementation | 10 | #pragma implementation |
11 | #endif | 11 | #endif |
12 | 12 | ||
13 | #include <aconf.h> | 13 | #include <aconf.h> |
14 | #include <stddef.h> | 14 | #include <stddef.h> |
15 | #include "Object.h" | 15 | #include "Object.h" |
16 | #include "Array.h" | 16 | #include "Array.h" |
17 | #include "Dict.h" | 17 | #include "Dict.h" |
18 | #include "Error.h" | 18 | #include "Error.h" |
19 | #include "Stream.h" | 19 | #include "Stream.h" |
20 | #include "XRef.h" | 20 | #include "XRef.h" |
21 | 21 | ||
22 | //------------------------------------------------------------------------ | 22 | //------------------------------------------------------------------------ |
23 | // Object | 23 | // Object |
24 | //------------------------------------------------------------------------ | 24 | //------------------------------------------------------------------------ |
25 | 25 | ||
26 | char *objTypeNames[numObjTypes] = { | 26 | char *objTypeNames[numObjTypes] = { |
27 | "boolean", | 27 | "boolean", |
28 | "integer", | 28 | "integer", |
29 | "real", | 29 | "real", |
30 | "string", | 30 | "string", |
31 | "name", | 31 | "name", |
32 | "null", | 32 | "null", |
33 | "array", | 33 | "array", |
34 | "dictionary", | 34 | "dictionary", |
35 | "stream", | 35 | "stream", |
36 | "ref", | 36 | "ref", |
37 | "cmd", | 37 | "cmd", |
38 | "error", | 38 | "error", |
39 | "eof", | 39 | "eof", |
40 | "none" | 40 | "none" |
41 | }; | 41 | }; |
42 | 42 | ||
43 | #ifdef DEBUG_MEM | 43 | #ifdef DEBUG_MEM |
44 | int Object::numAlloc[numObjTypes] = | 44 | int Object::numAlloc[numObjTypes] = |
45 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; | 45 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; |
46 | #endif | 46 | #endif |
47 | 47 | ||
48 | Object *Object::initArray(XRef *xref) { | 48 | Object *Object::initArray(XRef *xref) { |
49 | initObj(objArray); | 49 | initObj(objArray); |
50 | array = new Array(xref); | 50 | array = new Array(xref); |
51 | return this; | 51 | return this; |
52 | } | 52 | } |
53 | 53 | ||
54 | Object *Object::initDict(XRef *xref) { | 54 | Object *Object::initDict(XRef *xref) { |
55 | initObj(objDict); | 55 | initObj(objDict); |
56 | dict = new Dict(xref); | 56 | dict = new Dict(xref); |
57 | return this; | 57 | return this; |
58 | } | 58 | } |
59 | 59 | ||
60 | Object *Object::initStream(Stream *streamA) { | 60 | Object *Object::initStream(Stream *streamA) { |
61 | initObj(objStream); | 61 | initObj(objStream); |
62 | stream = streamA; | 62 | stream = streamA; |
63 | return this; | 63 | return this; |
64 | } | 64 | } |
65 | 65 | ||
66 | Object *Object::copy(Object *obj) { | 66 | Object *Object::copy(Object *obj) { |
67 | *obj = *this; | 67 | *obj = *this; |
68 | switch (type) { | 68 | switch (type) { |
69 | case objString: | 69 | case objString: |
70 | obj->string = string->copy(); | 70 | obj->string = string->copy(); |
71 | break; | 71 | break; |
72 | case objName: | 72 | case objName: |
73 | obj->name = copyString(name); | 73 | obj->name = copyString(name); |
74 | break; | 74 | break; |
75 | case objArray: | 75 | case objArray: |
76 | array->incRef(); | 76 | array->incRef(); |
77 | break; | 77 | break; |
78 | case objDict: | 78 | case objDict: |
79 | dict->incRef(); | 79 | dict->incRef(); |
80 | break; | 80 | break; |
81 | case objStream: | 81 | case objStream: |
82 | stream->incRef(); | 82 | stream->incRef(); |
83 | break; | 83 | break; |
84 | case objCmd: | 84 | case objCmd: |
85 | obj->cmd = copyString(cmd); | 85 | obj->cmd = copyString(cmd); |
86 | break; | 86 | break; |
87 | default: | 87 | default: |
88 | break; | 88 | break; |
89 | } | 89 | } |
90 | #ifdef DEBUG_MEM | 90 | #ifdef DEBUG_MEM |
91 | ++numAlloc[type]; | 91 | ++numAlloc[type]; |
92 | #endif | 92 | #endif |
93 | return obj; | 93 | return obj; |
94 | } | 94 | } |
95 | 95 | ||
96 | Object *Object::fetch(XRef *xref, Object *obj) { | 96 | Object *Object::fetch(XRef *xref, Object *obj) { |
97 | return (type == objRef && xref) ? | 97 | return (type == objRef && xref) ? |
98 | xref->fetch(ref.num, ref.gen, obj) : copy(obj); | 98 | xref->fetch(ref.num, ref.gen, obj) : copy(obj); |
99 | } | 99 | } |
100 | 100 | ||
101 | void Object::free() { | 101 | void Object::free() { |
102 | switch (type) { | 102 | switch (type) { |
103 | case objString: | 103 | case objString: |
104 | delete string; | 104 | delete string; |
105 | break; | 105 | break; |
106 | case objName: | 106 | case objName: |
107 | gfree(name); | 107 | gfree(name); |
108 | break; | 108 | break; |
109 | case objArray: | 109 | case objArray: |
110 | if (!array->decRef()) { | 110 | if (!array->decRef()) { |
111 | delete array; | 111 | delete array; |
112 | } | 112 | } |
113 | break; | 113 | break; |
114 | case objDict: | 114 | case objDict: |
115 | if (!dict->decRef()) { | 115 | if (!dict->decRef()) { |
116 | delete dict; | 116 | delete dict; |
117 | } | 117 | } |
118 | break; | 118 | break; |
119 | case objStream: | 119 | case objStream: |
120 | if (!stream->decRef()) { | 120 | if (!stream->decRef()) { |
121 | delete stream; | 121 | delete stream; |
122 | } | 122 | } |
123 | break; | 123 | break; |
124 | case objCmd: | 124 | case objCmd: |
125 | gfree(cmd); | 125 | gfree(cmd); |
126 | break; | 126 | break; |
127 | default: | 127 | default: |
128 | break; | 128 | break; |
129 | } | 129 | } |
130 | #ifdef DEBUG_MEM | 130 | #ifdef DEBUG_MEM |
131 | --numAlloc[type]; | 131 | --numAlloc[type]; |
132 | #endif | 132 | #endif |
133 | type = objNone; | 133 | type = objNone; |
134 | } | 134 | } |
135 | 135 | ||
136 | char *Object::getTypeName() { | 136 | char *Object::getTypeName() { |
137 | return objTypeNames[type]; | 137 | return objTypeNames[type]; |
138 | } | 138 | } |
139 | 139 | ||
140 | void Object::print(FILE *f) { | 140 | void Object::print(FILE *f) { |
141 | Object obj; | 141 | Object obj; |
142 | int i; | 142 | int i; |
143 | 143 | ||
144 | switch (type) { | 144 | switch (type) { |
145 | case objBool: | 145 | case objBool: |
146 | fprintf(f, "%s", booln ? "true" : "false"); | 146 | fprintf(f, "%s", booln ? "true" : "false"); |
147 | break; | 147 | break; |
148 | case objInt: | 148 | case objInt: |
149 | fprintf(f, "%d", intg); | 149 | fprintf(f, "%d", intg); |
150 | break; | 150 | break; |
151 | case objReal: | 151 | case objReal: |
152 | fprintf(f, "%g", real); | 152 | fprintf(f, "%g", static_cast<double>(real)); |
153 | break; | 153 | break; |
154 | case objString: | 154 | case objString: |
155 | fprintf(f, "("); | 155 | fprintf(f, "("); |
156 | fwrite(string->getCString(), 1, string->getLength(), stdout); | 156 | fwrite(string->getCString(), 1, string->getLength(), stdout); |
157 | fprintf(f, ")"); | 157 | fprintf(f, ")"); |
158 | break; | 158 | break; |
159 | case objName: | 159 | case objName: |
160 | fprintf(f, "/%s", name); | 160 | fprintf(f, "/%s", name); |
161 | break; | 161 | break; |
162 | case objNull: | 162 | case objNull: |
163 | fprintf(f, "null"); | 163 | fprintf(f, "null"); |
164 | break; | 164 | break; |
165 | case objArray: | 165 | case objArray: |
166 | fprintf(f, "["); | 166 | fprintf(f, "["); |
167 | for (i = 0; i < arrayGetLength(); ++i) { | 167 | for (i = 0; i < arrayGetLength(); ++i) { |
168 | if (i > 0) | 168 | if (i > 0) |
169 | fprintf(f, " "); | 169 | fprintf(f, " "); |
170 | arrayGetNF(i, &obj); | 170 | arrayGetNF(i, &obj); |
171 | obj.print(f); | 171 | obj.print(f); |
172 | obj.free(); | 172 | obj.free(); |
173 | } | 173 | } |
174 | fprintf(f, "]"); | 174 | fprintf(f, "]"); |
175 | break; | 175 | break; |
176 | case objDict: | 176 | case objDict: |
177 | fprintf(f, "<<"); | 177 | fprintf(f, "<<"); |
178 | for (i = 0; i < dictGetLength(); ++i) { | 178 | for (i = 0; i < dictGetLength(); ++i) { |
179 | fprintf(f, " /%s ", dictGetKey(i)); | 179 | fprintf(f, " /%s ", dictGetKey(i)); |
180 | dictGetValNF(i, &obj); | 180 | dictGetValNF(i, &obj); |
181 | obj.print(f); | 181 | obj.print(f); |
182 | obj.free(); | 182 | obj.free(); |
183 | } | 183 | } |
184 | fprintf(f, " >>"); | 184 | fprintf(f, " >>"); |
185 | break; | 185 | break; |
186 | case objStream: | 186 | case objStream: |
187 | fprintf(f, "<stream>"); | 187 | fprintf(f, "<stream>"); |
188 | break; | 188 | break; |
189 | case objRef: | 189 | case objRef: |
190 | fprintf(f, "%d %d R", ref.num, ref.gen); | 190 | fprintf(f, "%d %d R", ref.num, ref.gen); |
191 | break; | 191 | break; |
192 | case objCmd: | 192 | case objCmd: |
193 | fprintf(f, "%s", cmd); | 193 | fprintf(f, "%s", cmd); |
194 | break; | 194 | break; |
195 | case objError: | 195 | case objError: |
196 | fprintf(f, "<error>"); | 196 | fprintf(f, "<error>"); |
197 | break; | 197 | break; |
198 | case objEOF: | 198 | case objEOF: |
199 | fprintf(f, "<EOF>"); | 199 | fprintf(f, "<EOF>"); |
200 | break; | 200 | break; |
201 | case objNone: | 201 | case objNone: |
202 | fprintf(f, "<none>"); | 202 | fprintf(f, "<none>"); |
203 | break; | 203 | break; |
204 | } | 204 | } |
205 | } | 205 | } |
206 | 206 | ||
207 | void Object::memCheck(FILE *f) { | 207 | void Object::memCheck(FILE *f) { |
208 | #ifdef DEBUG_MEM | 208 | #ifdef DEBUG_MEM |
209 | int i; | 209 | int i; |
210 | int t; | 210 | int t; |
211 | 211 | ||
212 | t = 0; | 212 | t = 0; |
213 | for (i = 0; i < numObjTypes; ++i) | 213 | for (i = 0; i < numObjTypes; ++i) |
214 | t += numAlloc[i]; | 214 | t += numAlloc[i]; |
215 | if (t > 0) { | 215 | if (t > 0) { |
216 | fprintf(f, "Allocated objects:\n"); | 216 | fprintf(f, "Allocated objects:\n"); |
217 | for (i = 0; i < numObjTypes; ++i) { | 217 | for (i = 0; i < numObjTypes; ++i) { |
218 | if (numAlloc[i] > 0) | 218 | if (numAlloc[i] > 0) |
219 | fprintf(f, " %-20s: %6d\n", objTypeNames[i], numAlloc[i]); | 219 | fprintf(f, " %-20s: %6d\n", objTypeNames[i], numAlloc[i]); |
220 | } | 220 | } |
221 | } | 221 | } |
222 | #endif | 222 | #endif |
223 | } | 223 | } |
diff --git a/noncore/unsupported/qpdf/xpdf/Page.cc b/noncore/unsupported/qpdf/xpdf/Page.cc index 9cc08c4..aead7da 100644 --- a/noncore/unsupported/qpdf/xpdf/Page.cc +++ b/noncore/unsupported/qpdf/xpdf/Page.cc | |||
@@ -1,281 +1,281 @@ | |||
1 | //======================================================================== | 1 | //======================================================================== |
2 | // | 2 | // |
3 | // Page.cc | 3 | // Page.cc |
4 | // | 4 | // |
5 | // Copyright 1996-2002 Glyph & Cog, LLC | 5 | // Copyright 1996-2002 Glyph & Cog, LLC |
6 | // | 6 | // |
7 | //======================================================================== | 7 | //======================================================================== |
8 | 8 | ||
9 | #ifdef __GNUC__ | 9 | #ifdef __GNUC__ |
10 | #pragma implementation | 10 | #pragma implementation |
11 | #endif | 11 | #endif |
12 | 12 | ||
13 | #include <aconf.h> | 13 | #include <aconf.h> |
14 | #include <stddef.h> | 14 | #include <stddef.h> |
15 | #include "Object.h" | 15 | #include "Object.h" |
16 | #include "Array.h" | 16 | #include "Array.h" |
17 | #include "Dict.h" | 17 | #include "Dict.h" |
18 | #include "XRef.h" | 18 | #include "XRef.h" |
19 | #include "Link.h" | 19 | #include "Link.h" |
20 | #include "OutputDev.h" | 20 | #include "OutputDev.h" |
21 | #ifndef PDF_PARSER_ONLY | 21 | #ifndef PDF_PARSER_ONLY |
22 | #include "Gfx.h" | 22 | #include "Gfx.h" |
23 | #include "Annot.h" | 23 | #include "Annot.h" |
24 | #endif | 24 | #endif |
25 | #include "Error.h" | 25 | #include "Error.h" |
26 | #include "Page.h" | 26 | #include "Page.h" |
27 | 27 | ||
28 | //------------------------------------------------------------------------ | 28 | //------------------------------------------------------------------------ |
29 | // PageAttrs | 29 | // PageAttrs |
30 | //------------------------------------------------------------------------ | 30 | //------------------------------------------------------------------------ |
31 | 31 | ||
32 | PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { | 32 | PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { |
33 | Object obj1; | 33 | Object obj1; |
34 | fouble w, h; | 34 | fouble w, h; |
35 | 35 | ||
36 | // get old/default values | 36 | // get old/default values |
37 | if (attrs) { | 37 | if (attrs) { |
38 | mediaBox = attrs->mediaBox; | 38 | mediaBox = attrs->mediaBox; |
39 | cropBox = attrs->cropBox; | 39 | cropBox = attrs->cropBox; |
40 | haveCropBox = attrs->haveCropBox; | 40 | haveCropBox = attrs->haveCropBox; |
41 | rotate = attrs->rotate; | 41 | rotate = attrs->rotate; |
42 | attrs->resources.copy(&resources); | 42 | attrs->resources.copy(&resources); |
43 | } else { | 43 | } else { |
44 | // set default MediaBox to 8.5" x 11" -- this shouldn't be necessary | 44 | // set default MediaBox to 8.5" x 11" -- this shouldn't be necessary |
45 | // but some (non-compliant) PDF files don't specify a MediaBox | 45 | // but some (non-compliant) PDF files don't specify a MediaBox |
46 | mediaBox.x1 = 0; | 46 | mediaBox.x1 = 0; |
47 | mediaBox.y1 = 0; | 47 | mediaBox.y1 = 0; |
48 | mediaBox.x2 = 612; | 48 | mediaBox.x2 = 612; |
49 | mediaBox.y2 = 792; | 49 | mediaBox.y2 = 792; |
50 | cropBox.x1 = cropBox.y1 = cropBox.x2 = cropBox.y2 = 0; | 50 | cropBox.x1 = cropBox.y1 = cropBox.x2 = cropBox.y2 = 0; |
51 | haveCropBox = gFalse; | 51 | haveCropBox = gFalse; |
52 | rotate = 0; | 52 | rotate = 0; |
53 | resources.initNull(); | 53 | resources.initNull(); |
54 | } | 54 | } |
55 | 55 | ||
56 | // media box | 56 | // media box |
57 | readBox(dict, "MediaBox", &mediaBox); | 57 | readBox(dict, "MediaBox", &mediaBox); |
58 | 58 | ||
59 | // crop box | 59 | // crop box |
60 | cropBox = mediaBox; | 60 | cropBox = mediaBox; |
61 | haveCropBox = readBox(dict, "CropBox", &cropBox); | 61 | haveCropBox = readBox(dict, "CropBox", &cropBox); |
62 | 62 | ||
63 | // if the MediaBox is excessively larger than the CropBox, | 63 | // if the MediaBox is excessively larger than the CropBox, |
64 | // just use the CropBox | 64 | // just use the CropBox |
65 | limitToCropBox = gFalse; | 65 | limitToCropBox = gFalse; |
66 | if (haveCropBox) { | 66 | if (haveCropBox) { |
67 | w = 0.25 * (cropBox.x2 - cropBox.x1); | 67 | w = 0.25 * (cropBox.x2 - cropBox.x1); |
68 | h = 0.25 * (cropBox.y2 - cropBox.y1); | 68 | h = 0.25 * (cropBox.y2 - cropBox.y1); |
69 | if ((cropBox.x1 - mediaBox.x1) + (mediaBox.x2 - cropBox.x2) > w || | 69 | if ((cropBox.x1 - mediaBox.x1) + (mediaBox.x2 - cropBox.x2) > w || |
70 | (cropBox.y1 - mediaBox.y1) + (mediaBox.y2 - cropBox.y2) > h) { | 70 | (cropBox.y1 - mediaBox.y1) + (mediaBox.y2 - cropBox.y2) > h) { |
71 | limitToCropBox = gTrue; | 71 | limitToCropBox = gTrue; |
72 | } | 72 | } |
73 | } | 73 | } |
74 | 74 | ||
75 | // other boxes | 75 | // other boxes |
76 | bleedBox = cropBox; | 76 | bleedBox = cropBox; |
77 | readBox(dict, "BleedBox", &bleedBox); | 77 | readBox(dict, "BleedBox", &bleedBox); |
78 | trimBox = cropBox; | 78 | trimBox = cropBox; |
79 | readBox(dict, "TrimBox", &trimBox); | 79 | readBox(dict, "TrimBox", &trimBox); |
80 | artBox = cropBox; | 80 | artBox = cropBox; |
81 | readBox(dict, "ArtBox", &artBox); | 81 | readBox(dict, "ArtBox", &artBox); |
82 | 82 | ||
83 | // rotate | 83 | // rotate |
84 | dict->lookup("Rotate", &obj1); | 84 | dict->lookup("Rotate", &obj1); |
85 | if (obj1.isInt()) { | 85 | if (obj1.isInt()) { |
86 | rotate = obj1.getInt(); | 86 | rotate = obj1.getInt(); |
87 | } | 87 | } |
88 | obj1.free(); | 88 | obj1.free(); |
89 | while (rotate < 0) { | 89 | while (rotate < 0) { |
90 | rotate += 360; | 90 | rotate += 360; |
91 | } | 91 | } |
92 | while (rotate >= 360) { | 92 | while (rotate >= 360) { |
93 | rotate -= 360; | 93 | rotate -= 360; |
94 | } | 94 | } |
95 | 95 | ||
96 | // misc attributes | 96 | // misc attributes |
97 | dict->lookup("LastModified", &lastModified); | 97 | dict->lookup("LastModified", &lastModified); |
98 | dict->lookup("BoxColorInfo", &boxColorInfo); | 98 | dict->lookup("BoxColorInfo", &boxColorInfo); |
99 | dict->lookup("Group", &group); | 99 | dict->lookup("Group", &group); |
100 | dict->lookup("Metadata", &metadata); | 100 | dict->lookup("Metadata", &metadata); |
101 | dict->lookup("PieceInfo", &pieceInfo); | 101 | dict->lookup("PieceInfo", &pieceInfo); |
102 | dict->lookup("SeparationInfo", &separationInfo); | 102 | dict->lookup("SeparationInfo", &separationInfo); |
103 | 103 | ||
104 | // resource dictionary | 104 | // resource dictionary |
105 | dict->lookup("Resources", &obj1); | 105 | dict->lookup("Resources", &obj1); |
106 | if (obj1.isDict()) { | 106 | if (obj1.isDict()) { |
107 | resources.free(); | 107 | resources.free(); |
108 | obj1.copy(&resources); | 108 | obj1.copy(&resources); |
109 | } | 109 | } |
110 | obj1.free(); | 110 | obj1.free(); |
111 | } | 111 | } |
112 | 112 | ||
113 | PageAttrs::~PageAttrs() { | 113 | PageAttrs::~PageAttrs() { |
114 | lastModified.free(); | 114 | lastModified.free(); |
115 | boxColorInfo.free(); | 115 | boxColorInfo.free(); |
116 | group.free(); | 116 | group.free(); |
117 | metadata.free(); | 117 | metadata.free(); |
118 | pieceInfo.free(); | 118 | pieceInfo.free(); |
119 | separationInfo.free(); | 119 | separationInfo.free(); |
120 | resources.free(); | 120 | resources.free(); |
121 | } | 121 | } |
122 | 122 | ||
123 | GBool PageAttrs::readBox(Dict *dict, char *key, PDFRectangle *box) { | 123 | GBool PageAttrs::readBox(Dict *dict, char *key, PDFRectangle *box) { |
124 | PDFRectangle tmp; | 124 | PDFRectangle tmp; |
125 | Object obj1, obj2; | 125 | Object obj1, obj2; |
126 | GBool ok; | 126 | GBool ok; |
127 | 127 | ||
128 | dict->lookup(key, &obj1); | 128 | dict->lookup(key, &obj1); |
129 | if (obj1.isArray() && obj1.arrayGetLength() == 4) { | 129 | if (obj1.isArray() && obj1.arrayGetLength() == 4) { |
130 | ok = gTrue; | 130 | ok = gTrue; |
131 | obj1.arrayGet(0, &obj2); | 131 | obj1.arrayGet(0, &obj2); |
132 | if (obj2.isNum()) { | 132 | if (obj2.isNum()) { |
133 | tmp.x1 = obj2.getNum(); | 133 | tmp.x1 = obj2.getNum(); |
134 | } else { | 134 | } else { |
135 | ok = gFalse; | 135 | ok = gFalse; |
136 | } | 136 | } |
137 | obj2.free(); | 137 | obj2.free(); |
138 | obj1.arrayGet(1, &obj2); | 138 | obj1.arrayGet(1, &obj2); |
139 | if (obj2.isNum()) { | 139 | if (obj2.isNum()) { |
140 | tmp.y1 = obj2.getNum(); | 140 | tmp.y1 = obj2.getNum(); |
141 | } else { | 141 | } else { |
142 | ok = gFalse; | 142 | ok = gFalse; |
143 | } | 143 | } |
144 | obj2.free(); | 144 | obj2.free(); |
145 | obj1.arrayGet(2, &obj2); | 145 | obj1.arrayGet(2, &obj2); |
146 | if (obj2.isNum()) { | 146 | if (obj2.isNum()) { |
147 | tmp.x2 = obj2.getNum(); | 147 | tmp.x2 = obj2.getNum(); |
148 | } else { | 148 | } else { |
149 | ok = gFalse; | 149 | ok = gFalse; |
150 | } | 150 | } |
151 | obj2.free(); | 151 | obj2.free(); |
152 | obj1.arrayGet(3, &obj2); | 152 | obj1.arrayGet(3, &obj2); |
153 | if (obj2.isNum()) { | 153 | if (obj2.isNum()) { |
154 | tmp.y2 = obj2.getNum(); | 154 | tmp.y2 = obj2.getNum(); |
155 | } else { | 155 | } else { |
156 | ok = gFalse; | 156 | ok = gFalse; |
157 | } | 157 | } |
158 | obj2.free(); | 158 | obj2.free(); |
159 | if (ok) { | 159 | if (ok) { |
160 | *box = tmp; | 160 | *box = tmp; |
161 | } | 161 | } |
162 | } else { | 162 | } else { |
163 | ok = gFalse; | 163 | ok = gFalse; |
164 | } | 164 | } |
165 | obj1.free(); | 165 | obj1.free(); |
166 | return ok; | 166 | return ok; |
167 | } | 167 | } |
168 | 168 | ||
169 | //------------------------------------------------------------------------ | 169 | //------------------------------------------------------------------------ |
170 | // Page | 170 | // Page |
171 | //------------------------------------------------------------------------ | 171 | //------------------------------------------------------------------------ |
172 | 172 | ||
173 | Page::Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA, | 173 | Page::Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA, |
174 | GBool printCommandsA) { | 174 | GBool printCommandsA) { |
175 | 175 | ||
176 | ok = gTrue; | 176 | ok = gTrue; |
177 | xref = xrefA; | 177 | xref = xrefA; |
178 | num = numA; | 178 | num = numA; |
179 | printCommands = printCommandsA; | 179 | printCommands = printCommandsA; |
180 | 180 | ||
181 | // get attributes | 181 | // get attributes |
182 | attrs = attrsA; | 182 | attrs = attrsA; |
183 | 183 | ||
184 | // annotations | 184 | // annotations |
185 | pageDict->lookupNF("Annots", &annots); | 185 | pageDict->lookupNF("Annots", &annots); |
186 | if (!(annots.isRef() || annots.isArray() || annots.isNull())) { | 186 | if (!(annots.isRef() || annots.isArray() || annots.isNull())) { |
187 | error(-1, "Page annotations object (page %d) is wrong type (%s)", | 187 | error(-1, "Page annotations object (page %d) is wrong type (%s)", |
188 | num, annots.getTypeName()); | 188 | num, annots.getTypeName()); |
189 | annots.free(); | 189 | annots.free(); |
190 | goto err2; | 190 | goto err2; |
191 | } | 191 | } |
192 | 192 | ||
193 | // contents | 193 | // contents |
194 | pageDict->lookupNF("Contents", &contents); | 194 | pageDict->lookupNF("Contents", &contents); |
195 | if (!(contents.isRef() || contents.isArray() || | 195 | if (!(contents.isRef() || contents.isArray() || |
196 | contents.isNull())) { | 196 | contents.isNull())) { |
197 | error(-1, "Page contents object (page %d) is wrong type (%s)", | 197 | error(-1, "Page contents object (page %d) is wrong type (%s)", |
198 | num, contents.getTypeName()); | 198 | num, contents.getTypeName()); |
199 | contents.free(); | 199 | contents.free(); |
200 | goto err1; | 200 | goto err1; |
201 | } | 201 | } |
202 | 202 | ||
203 | return; | 203 | return; |
204 | 204 | ||
205 | err2: | 205 | err2: |
206 | annots.initNull(); | 206 | annots.initNull(); |
207 | err1: | 207 | err1: |
208 | contents.initNull(); | 208 | contents.initNull(); |
209 | ok = gFalse; | 209 | ok = gFalse; |
210 | } | 210 | } |
211 | 211 | ||
212 | Page::~Page() { | 212 | Page::~Page() { |
213 | delete attrs; | 213 | delete attrs; |
214 | annots.free(); | 214 | annots.free(); |
215 | contents.free(); | 215 | contents.free(); |
216 | } | 216 | } |
217 | 217 | ||
218 | void Page::display(OutputDev *out, fouble dpi, int rotate, | 218 | void Page::display(OutputDev *out, fouble dpi, int rotate, |
219 | Links *links, Catalog *catalog) { | 219 | Links *links, Catalog *catalog) { |
220 | #ifndef PDF_PARSER_ONLY | 220 | #ifndef PDF_PARSER_ONLY |
221 | PDFRectangle *box, *cropBox; | 221 | PDFRectangle *box, *cropBox; |
222 | Gfx *gfx; | 222 | Gfx *gfx; |
223 | Object obj; | 223 | Object obj; |
224 | Link *link; | 224 | Link *link; |
225 | int i; | 225 | int i; |
226 | Annots *annotList; | 226 | Annots *annotList; |
227 | 227 | ||
228 | box = getBox(); | 228 | box = getBox(); |
229 | cropBox = getCropBox(); | 229 | cropBox = getCropBox(); |
230 | 230 | ||
231 | if (printCommands) { | 231 | if (printCommands) { |
232 | printf("***** MediaBox = ll:%g,%g ur:%g,%g\n", | 232 | printf("***** MediaBox = ll:%g,%g ur:%g,%g\n", |
233 | box->x1, box->y1, box->x2, box->y2); | 233 | static_cast<double>(box->x1), static_cast<double>(box->y1), static_cast<double>(box->x2), static_cast<double>(box->y2)); |
234 | if (isCropped()) { | 234 | if (isCropped()) { |
235 | printf("***** CropBox = ll:%g,%g ur:%g,%g\n", | 235 | printf("***** CropBox = ll:%g,%g ur:%g,%g\n", |
236 | cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2); | 236 | static_cast<double>(cropBox->x1), static_cast<double>(cropBox->y1), static_cast<double>(cropBox->x2), static_cast<double>(cropBox->y2)); |
237 | } | 237 | } |
238 | printf("***** Rotate = %d\n", attrs->getRotate()); | 238 | printf("***** Rotate = %d\n", attrs->getRotate()); |
239 | } | 239 | } |
240 | 240 | ||
241 | rotate += getRotate(); | 241 | rotate += getRotate(); |
242 | if (rotate >= 360) { | 242 | if (rotate >= 360) { |
243 | rotate -= 360; | 243 | rotate -= 360; |
244 | } else if (rotate < 0) { | 244 | } else if (rotate < 0) { |
245 | rotate += 360; | 245 | rotate += 360; |
246 | } | 246 | } |
247 | gfx = new Gfx(xref, out, num, attrs->getResourceDict(), | 247 | gfx = new Gfx(xref, out, num, attrs->getResourceDict(), |
248 | dpi, box, isCropped(), cropBox, rotate, printCommands); | 248 | dpi, box, isCropped(), cropBox, rotate, printCommands); |
249 | contents.fetch(xref, &obj); | 249 | contents.fetch(xref, &obj); |
250 | if (!obj.isNull()) { | 250 | if (!obj.isNull()) { |
251 | gfx->display(&obj); | 251 | gfx->display(&obj); |
252 | } | 252 | } |
253 | obj.free(); | 253 | obj.free(); |
254 | 254 | ||
255 | // draw links | 255 | // draw links |
256 | if (links) { | 256 | if (links) { |
257 | for (i = 0; i < links->getNumLinks(); ++i) { | 257 | for (i = 0; i < links->getNumLinks(); ++i) { |
258 | link = links->getLink(i); | 258 | link = links->getLink(i); |
259 | out->drawLink(link, catalog); | 259 | out->drawLink(link, catalog); |
260 | } | 260 | } |
261 | out->dump(); | 261 | out->dump(); |
262 | } | 262 | } |
263 | 263 | ||
264 | // draw non-link annotations | 264 | // draw non-link annotations |
265 | //~ need to reset CTM ??? | 265 | //~ need to reset CTM ??? |
266 | annotList = new Annots(xref, annots.fetch(xref, &obj)); | 266 | annotList = new Annots(xref, annots.fetch(xref, &obj)); |
267 | obj.free(); | 267 | obj.free(); |
268 | if (annotList->getNumAnnots() > 0) { | 268 | if (annotList->getNumAnnots() > 0) { |
269 | if (printCommands) { | 269 | if (printCommands) { |
270 | printf("***** Annotations\n"); | 270 | printf("***** Annotations\n"); |
271 | } | 271 | } |
272 | for (i = 0; i < annotList->getNumAnnots(); ++i) { | 272 | for (i = 0; i < annotList->getNumAnnots(); ++i) { |
273 | annotList->getAnnot(i)->draw(gfx); | 273 | annotList->getAnnot(i)->draw(gfx); |
274 | } | 274 | } |
275 | out->dump(); | 275 | out->dump(); |
276 | } | 276 | } |
277 | delete annotList; | 277 | delete annotList; |
278 | 278 | ||
279 | delete gfx; | 279 | delete gfx; |
280 | #endif | 280 | #endif |
281 | } | 281 | } |