OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2006 The Android Open Source Project | 2 * Copyright 2006 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkBuffer.h" | 8 #include "SkBuffer.h" |
9 #include "SkErrorInternals.h" | 9 #include "SkErrorInternals.h" |
10 #include "SkGeometry.h" | 10 #include "SkGeometry.h" |
(...skipping 957 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
968 } | 968 } |
969 #endif | 969 #endif |
970 | 970 |
971 void SkPath::addRoundRect(const SkRect& rect, const SkScalar radii[], | 971 void SkPath::addRoundRect(const SkRect& rect, const SkScalar radii[], |
972 Direction dir) { | 972 Direction dir) { |
973 SkRRect rrect; | 973 SkRRect rrect; |
974 rrect.setRectRadii(rect, (const SkVector*) radii); | 974 rrect.setRectRadii(rect, (const SkVector*) radii); |
975 this->addRRect(rrect, dir); | 975 this->addRRect(rrect, dir); |
976 } | 976 } |
977 | 977 |
978 #ifdef SK_SUPPORT_LEGACY_ADDRRECT | |
979 /* The inline clockwise and counterclockwise round rect quad approximations | |
980 make it easier to see the symmetry patterns used by add corner quads. | |
981 Clockwise corner value | |
982 path->lineTo(rect.fLeft, rect.fTop + ry); 0 upper left | |
983 path->quadTo(rect.fLeft, rect.fTop + offPtY, | |
984 rect.fLeft + midPtX, rect.fTop + midPtY); | |
985 path->quadTo(rect.fLeft + offPtX, rect.fTop, | |
986 rect.fLeft + rx, rect.fTop); | |
987 | |
988 path->lineTo(rect.fRight - rx, rect.fTop); 1 upper right | |
989 path->quadTo(rect.fRight - offPtX, rect.fTop, | |
990 rect.fRight - midPtX, rect.fTop + midPtY); | |
991 path->quadTo(rect.fRight, rect.fTop + offPtY, | |
992 rect.fRight, rect.fTop + ry); | |
993 | |
994 path->lineTo(rect.fRight, rect.fBottom - ry); 2 lower right | |
995 path->quadTo(rect.fRight, rect.fBottom - offPtY, | |
996 rect.fRight - midPtX, rect.fBottom - midPtY); | |
997 path->quadTo(rect.fRight - offPtX, rect.fBottom, | |
998 rect.fRight - rx, rect.fBottom); | |
999 | |
1000 path->lineTo(rect.fLeft + rx, rect.fBottom); 3 lower left | |
1001 path->quadTo(rect.fLeft + offPtX, rect.fBottom, | |
1002 rect.fLeft + midPtX, rect.fBottom - midPtY); | |
1003 path->quadTo(rect.fLeft, rect.fBottom - offPtY, | |
1004 rect.fLeft, rect.fBottom - ry); | |
1005 | |
1006 Counterclockwise | |
1007 path->lineTo(rect.fLeft, rect.fBottom - ry); 3 lower left | |
1008 path->quadTo(rect.fLeft, rect.fBottom - offPtY, | |
1009 rect.fLeft + midPtX, rect.fBottom - midPtY); | |
1010 path->quadTo(rect.fLeft + offPtX, rect.fBottom, | |
1011 rect.fLeft + rx, rect.fBottom); | |
1012 | |
1013 path->lineTo(rect.fRight - rx, rect.fBottom); 2 lower right | |
1014 path->quadTo(rect.fRight - offPtX, rect.fBottom, | |
1015 rect.fRight - midPtX, rect.fBottom - midPtY); | |
1016 path->quadTo(rect.fRight, rect.fBottom - offPtY, | |
1017 rect.fRight, rect.fBottom - ry); | |
1018 | |
1019 path->lineTo(rect.fRight, rect.fTop + ry); 1 upper right | |
1020 path->quadTo(rect.fRight, rect.fTop + offPtY, | |
1021 rect.fRight - midPtX, rect.fTop + midPtY); | |
1022 path->quadTo(rect.fRight - offPtX, rect.fTop, | |
1023 rect.fRight - rx, rect.fTop); | |
1024 | |
1025 path->lineTo(rect.fLeft + rx, rect.fTop); 0 upper left | |
1026 path->quadTo(rect.fLeft + offPtX, rect.fTop, | |
1027 rect.fLeft + midPtX, rect.fTop + midPtY); | |
1028 path->quadTo(rect.fLeft, rect.fTop + offPtY, | |
1029 rect.fLeft, rect.fTop + ry); | |
1030 */ | |
1031 static void add_corner_quads(SkPath* path, const SkRRect& rrect, | |
1032 SkRRect::Corner corner, SkPath::Direction dir) { | |
1033 const SkRect& rect = rrect.rect(); | |
1034 const SkVector& radii = rrect.radii(corner); | |
1035 SkScalar rx = radii.fX; | |
1036 SkScalar ry = radii.fY; | |
1037 // The mid point of the quadratic arc approximation is half way between the
two | |
1038 // control points. | |
1039 const SkScalar mid = 1 - (SK_Scalar1 + SK_ScalarTanPIOver8) / 2; | |
1040 SkScalar midPtX = rx * mid; | |
1041 SkScalar midPtY = ry * mid; | |
1042 const SkScalar control = 1 - SK_ScalarTanPIOver8; | |
1043 SkScalar offPtX = rx * control; | |
1044 SkScalar offPtY = ry * control; | |
1045 static const int kCornerPts = 5; | |
1046 SkScalar xOff[kCornerPts]; | |
1047 SkScalar yOff[kCornerPts]; | |
1048 | |
1049 if ((corner & 1) == (dir == SkPath::kCCW_Direction)) { // corners always al
ternate direction | |
1050 SkASSERT(dir == SkPath::kCCW_Direction | |
1051 ? corner == SkRRect::kLowerLeft_Corner || corner == SkRRect::kUpper
Right_Corner | |
1052 : corner == SkRRect::kUpperLeft_Corner || corner == SkRRect::kLower
Right_Corner); | |
1053 xOff[0] = xOff[1] = 0; | |
1054 xOff[2] = midPtX; | |
1055 xOff[3] = offPtX; | |
1056 xOff[4] = rx; | |
1057 yOff[0] = ry; | |
1058 yOff[1] = offPtY; | |
1059 yOff[2] = midPtY; | |
1060 yOff[3] = yOff[4] = 0; | |
1061 } else { | |
1062 xOff[0] = rx; | |
1063 xOff[1] = offPtX; | |
1064 xOff[2] = midPtX; | |
1065 xOff[3] = xOff[4] = 0; | |
1066 yOff[0] = yOff[1] = 0; | |
1067 yOff[2] = midPtY; | |
1068 yOff[3] = offPtY; | |
1069 yOff[4] = ry; | |
1070 } | |
1071 if ((corner - 1) & 2) { | |
1072 SkASSERT(corner == SkRRect::kLowerLeft_Corner || corner == SkRRect::kUpp
erLeft_Corner); | |
1073 for (int i = 0; i < kCornerPts; ++i) { | |
1074 xOff[i] = rect.fLeft + xOff[i]; | |
1075 } | |
1076 } else { | |
1077 SkASSERT(corner == SkRRect::kLowerRight_Corner || corner == SkRRect::kUp
perRight_Corner); | |
1078 for (int i = 0; i < kCornerPts; ++i) { | |
1079 xOff[i] = rect.fRight - xOff[i]; | |
1080 } | |
1081 } | |
1082 if (corner < SkRRect::kLowerRight_Corner) { | |
1083 for (int i = 0; i < kCornerPts; ++i) { | |
1084 yOff[i] = rect.fTop + yOff[i]; | |
1085 } | |
1086 } else { | |
1087 for (int i = 0; i < kCornerPts; ++i) { | |
1088 yOff[i] = rect.fBottom - yOff[i]; | |
1089 } | |
1090 } | |
1091 | |
1092 SkPoint lastPt; | |
1093 SkAssertResult(path->getLastPt(&lastPt)); | |
1094 if (lastPt.fX != xOff[0] || lastPt.fY != yOff[0]) { | |
1095 path->lineTo(xOff[0], yOff[0]); | |
1096 } | |
1097 if (rx || ry) { | |
1098 path->quadTo(xOff[1], yOff[1], xOff[2], yOff[2]); | |
1099 path->quadTo(xOff[3], yOff[3], xOff[4], yOff[4]); | |
1100 } else { | |
1101 path->lineTo(xOff[2], yOff[2]); | |
1102 path->lineTo(xOff[4], yOff[4]); | |
1103 } | |
1104 } | |
1105 #endif | |
1106 | |
1107 void SkPath::addRRect(const SkRRect& rrect, Direction dir) { | 978 void SkPath::addRRect(const SkRRect& rrect, Direction dir) { |
1108 assert_known_direction(dir); | 979 assert_known_direction(dir); |
1109 | 980 |
1110 if (rrect.isEmpty()) { | 981 if (rrect.isEmpty()) { |
1111 return; | 982 return; |
1112 } | 983 } |
1113 | 984 |
1114 const SkRect& bounds = rrect.getBounds(); | 985 const SkRect& bounds = rrect.getBounds(); |
1115 | 986 |
1116 if (rrect.isRect()) { | 987 if (rrect.isRect()) { |
1117 this->addRect(bounds, dir); | 988 this->addRect(bounds, dir); |
1118 } else if (rrect.isOval()) { | 989 } else if (rrect.isOval()) { |
1119 this->addOval(bounds, dir); | 990 this->addOval(bounds, dir); |
1120 } else { | 991 } else { |
1121 fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction; | 992 fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction; |
1122 | 993 |
1123 SkAutoPathBoundsUpdate apbu(this, bounds); | 994 SkAutoPathBoundsUpdate apbu(this, bounds); |
1124 SkAutoDisableDirectionCheck addc(this); | 995 SkAutoDisableDirectionCheck addc(this); |
1125 | 996 |
1126 #ifdef SK_SUPPORT_LEGACY_ADDRRECT | |
1127 this->incReserve(21); | |
1128 if (kCW_Direction == dir) { | |
1129 this->moveTo(bounds.fLeft, | |
1130 bounds.fBottom - rrect.fRadii[SkRRect::kLowerLeft_Corne
r].fY); | |
1131 add_corner_quads(this, rrect, SkRRect::kUpperLeft_Corner, dir); | |
1132 add_corner_quads(this, rrect, SkRRect::kUpperRight_Corner, dir); | |
1133 add_corner_quads(this, rrect, SkRRect::kLowerRight_Corner, dir); | |
1134 add_corner_quads(this, rrect, SkRRect::kLowerLeft_Corner, dir); | |
1135 } else { | |
1136 this->moveTo(bounds.fLeft, | |
1137 bounds.fTop + rrect.fRadii[SkRRect::kUpperLeft_Corner].
fY); | |
1138 add_corner_quads(this, rrect, SkRRect::kLowerLeft_Corner, dir); | |
1139 add_corner_quads(this, rrect, SkRRect::kLowerRight_Corner, dir); | |
1140 add_corner_quads(this, rrect, SkRRect::kUpperRight_Corner, dir); | |
1141 add_corner_quads(this, rrect, SkRRect::kUpperLeft_Corner, dir); | |
1142 } | |
1143 #else | |
1144 const SkScalar L = bounds.fLeft; | 997 const SkScalar L = bounds.fLeft; |
1145 const SkScalar T = bounds.fTop; | 998 const SkScalar T = bounds.fTop; |
1146 const SkScalar R = bounds.fRight; | 999 const SkScalar R = bounds.fRight; |
1147 const SkScalar B = bounds.fBottom; | 1000 const SkScalar B = bounds.fBottom; |
1148 const SkScalar W = SK_ScalarRoot2Over2; | 1001 const SkScalar W = SK_ScalarRoot2Over2; |
1149 | 1002 |
1150 this->incReserve(13); | 1003 this->incReserve(13); |
1151 if (kCW_Direction == dir) { | 1004 if (kCW_Direction == dir) { |
1152 this->moveTo(L, B - rrect.fRadii[SkRRect::kLowerLeft_Corner].fY); | 1005 this->moveTo(L, B - rrect.fRadii[SkRRect::kLowerLeft_Corner].fY); |
1153 | 1006 |
(...skipping 16 matching lines...) Expand all Loading... |
1170 | 1023 |
1171 this->lineTo(R - rrect.fRadii[SkRRect::kLowerRight_Corner].fX, B); | 1024 this->lineTo(R - rrect.fRadii[SkRRect::kLowerRight_Corner].fX, B); |
1172 this->conicTo(R, B, R, B - rrect.fRadii[SkRRect::kLowerRight_Corner]
.fY, W); | 1025 this->conicTo(R, B, R, B - rrect.fRadii[SkRRect::kLowerRight_Corner]
.fY, W); |
1173 | 1026 |
1174 this->lineTo(R, T + rrect.fRadii[SkRRect::kUpperRight_Corner].fY); | 1027 this->lineTo(R, T + rrect.fRadii[SkRRect::kUpperRight_Corner].fY); |
1175 this->conicTo(R, T, R - rrect.fRadii[SkRRect::kUpperRight_Corner].fX
, T, W); | 1028 this->conicTo(R, T, R - rrect.fRadii[SkRRect::kUpperRight_Corner].fX
, T, W); |
1176 | 1029 |
1177 this->lineTo(L + rrect.fRadii[SkRRect::kUpperLeft_Corner].fX, T); | 1030 this->lineTo(L + rrect.fRadii[SkRRect::kUpperLeft_Corner].fX, T); |
1178 this->conicTo(L, T, L, T + rrect.fRadii[SkRRect::kUpperLeft_Corner].
fY, W); | 1031 this->conicTo(L, T, L, T + rrect.fRadii[SkRRect::kUpperLeft_Corner].
fY, W); |
1179 } | 1032 } |
1180 #endif | |
1181 this->close(); | 1033 this->close(); |
1182 } | 1034 } |
1183 SkDEBUGCODE(fPathRef->validate();) | 1035 SkDEBUGCODE(fPathRef->validate();) |
1184 } | 1036 } |
1185 | 1037 |
1186 bool SkPath::hasOnlyMoveTos() const { | 1038 bool SkPath::hasOnlyMoveTos() const { |
1187 int count = fPathRef->countVerbs(); | 1039 int count = fPathRef->countVerbs(); |
1188 const uint8_t* verbs = const_cast<const SkPathRef*>(fPathRef.get())->verbsMe
mBegin(); | 1040 const uint8_t* verbs = const_cast<const SkPathRef*>(fPathRef.get())->verbsMe
mBegin(); |
1189 for (int i = 0; i < count; ++i) { | 1041 for (int i = 0; i < count; ++i) { |
1190 if (*verbs == kLine_Verb || | 1042 if (*verbs == kLine_Verb || |
(...skipping 1754 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2945 switch (this->getFillType()) { | 2797 switch (this->getFillType()) { |
2946 case SkPath::kEvenOdd_FillType: | 2798 case SkPath::kEvenOdd_FillType: |
2947 case SkPath::kInverseEvenOdd_FillType: | 2799 case SkPath::kInverseEvenOdd_FillType: |
2948 w &= 1; | 2800 w &= 1; |
2949 break; | 2801 break; |
2950 default: | 2802 default: |
2951 break; | 2803 break; |
2952 } | 2804 } |
2953 return SkToBool(w); | 2805 return SkToBool(w); |
2954 } | 2806 } |
OLD | NEW |