OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/paint/BoxBorderPainter.h" | 5 #include "core/paint/BoxBorderPainter.h" |
6 | 6 |
7 #include "core/paint/BoxPainter.h" | 7 #include "core/paint/BoxPainter.h" |
8 #include "core/paint/ObjectPainter.h" | 8 #include "core/paint/ObjectPainter.h" |
9 #include "core/paint/PaintInfo.h" | 9 #include "core/paint/PaintInfo.h" |
10 #include "core/style/BorderEdge.h" | 10 #include "core/style/BorderEdge.h" |
(...skipping 1106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1117 if (!adjustedInnerRect.isEmpty()) | 1117 if (!adjustedInnerRect.isEmpty()) |
1118 graphicsContext.clipOutRoundedRect(adjustedInnerRect); | 1118 graphicsContext.clipOutRoundedRect(adjustedInnerRect); |
1119 } | 1119 } |
1120 | 1120 |
1121 void BoxBorderPainter::clipBorderSidePolygon(GraphicsContext& graphicsContext, | 1121 void BoxBorderPainter::clipBorderSidePolygon(GraphicsContext& graphicsContext, |
1122 BoxSide side, | 1122 BoxSide side, |
1123 MiterType firstMiter, | 1123 MiterType firstMiter, |
1124 MiterType secondMiter) const { | 1124 MiterType secondMiter) const { |
1125 DCHECK(firstMiter != NoMiter || secondMiter != NoMiter); | 1125 DCHECK(firstMiter != NoMiter || secondMiter != NoMiter); |
1126 | 1126 |
1127 FloatPoint quad[4]; | 1127 FloatPoint edgeQuad[4]; // The boundary of the edge for fill |
| 1128 FloatPoint boundQuad1; // Point 1 of the rectilinear bounding box of EdgeQuad |
| 1129 FloatPoint boundQuad2; // Point 2 of the rectilinear bounding box of EdgeQuad |
1128 | 1130 |
1129 const LayoutRect outerRect(m_outer.rect()); | 1131 const LayoutRect outerRect(m_outer.rect()); |
1130 const LayoutRect innerRect(m_inner.rect()); | 1132 const LayoutRect innerRect(m_inner.rect()); |
1131 | 1133 |
1132 // For each side, create a quad that encompasses all parts of that side that | 1134 // For each side, create a quad that encompasses all parts of that side that |
1133 // may draw, including areas inside the innerBorder. | 1135 // may draw, including areas inside the innerBorder. |
1134 // | 1136 // |
1135 // 0----------------3 | 1137 // 0----------------3 |
1136 // 0 \ / 0 | 1138 // 3 \ / 0 |
1137 // |\ 1----------- 2 /| | 1139 // |\ 1----------- 2 /| |
1138 // | 1 1 | | 1140 // | 2 1 | |
1139 // | | | | | 1141 // | | | | |
1140 // | | | | | 1142 // | | | | |
1141 // | 2 2 | | 1143 // | 1 2 | |
1142 // |/ 1------------2 \| | 1144 // |/ 2------------1 \| |
1143 // 3 / \ 3 | 1145 // 0 / \ 3 |
1144 // 0----------------3 | 1146 // 3----------------0 |
1145 // | 1147 |
| 1148 // Offset size and direction to expand clipping quad |
| 1149 const static float kExtensionLength = 1e-1f; |
| 1150 FloatSize extensionOffset; |
1146 switch (side) { | 1151 switch (side) { |
1147 case BSTop: | 1152 case BSTop: |
1148 quad[0] = FloatPoint(outerRect.minXMinYCorner()); | 1153 edgeQuad[0] = FloatPoint(outerRect.minXMinYCorner()); |
1149 quad[1] = FloatPoint(innerRect.minXMinYCorner()); | 1154 edgeQuad[1] = FloatPoint(innerRect.minXMinYCorner()); |
1150 quad[2] = FloatPoint(innerRect.maxXMinYCorner()); | 1155 edgeQuad[2] = FloatPoint(innerRect.maxXMinYCorner()); |
1151 quad[3] = FloatPoint(outerRect.maxXMinYCorner()); | 1156 edgeQuad[3] = FloatPoint(outerRect.maxXMinYCorner()); |
| 1157 |
| 1158 DCHECK(edgeQuad[0].y() == edgeQuad[3].y()); |
| 1159 DCHECK(edgeQuad[1].y() == edgeQuad[2].y()); |
| 1160 |
| 1161 boundQuad1 = FloatPoint(edgeQuad[0].x(), edgeQuad[1].y()); |
| 1162 boundQuad2 = FloatPoint(edgeQuad[3].x(), edgeQuad[2].y()); |
| 1163 |
| 1164 extensionOffset.setWidth(-kExtensionLength); |
| 1165 extensionOffset.setHeight(0); |
1152 | 1166 |
1153 if (!m_inner.getRadii().topLeft().isZero()) { | 1167 if (!m_inner.getRadii().topLeft().isZero()) { |
1154 findIntersection( | 1168 findIntersection( |
1155 quad[0], quad[1], | 1169 edgeQuad[0], edgeQuad[1], |
1156 FloatPoint(quad[1].x() + m_inner.getRadii().topLeft().width(), | 1170 FloatPoint(edgeQuad[1].x() + m_inner.getRadii().topLeft().width(), |
1157 quad[1].y()), | 1171 edgeQuad[1].y()), |
1158 FloatPoint(quad[1].x(), | 1172 FloatPoint(edgeQuad[1].x(), |
1159 quad[1].y() + m_inner.getRadii().topLeft().height()), | 1173 edgeQuad[1].y() + m_inner.getRadii().topLeft().height()), |
1160 quad[1]); | 1174 edgeQuad[1]); |
| 1175 DCHECK(boundQuad1.y() <= edgeQuad[1].y()); |
| 1176 boundQuad1.setY(edgeQuad[1].y()); |
| 1177 boundQuad2.setY(edgeQuad[1].y()); |
1161 } | 1178 } |
1162 | 1179 |
1163 if (!m_inner.getRadii().topRight().isZero()) { | 1180 if (!m_inner.getRadii().topRight().isZero()) { |
1164 findIntersection( | 1181 findIntersection( |
1165 quad[3], quad[2], | 1182 edgeQuad[3], edgeQuad[2], |
1166 FloatPoint(quad[2].x() - m_inner.getRadii().topRight().width(), | 1183 FloatPoint(edgeQuad[2].x() - m_inner.getRadii().topRight().width(), |
1167 quad[2].y()), | 1184 edgeQuad[2].y()), |
1168 FloatPoint(quad[2].x(), | 1185 FloatPoint( |
1169 quad[2].y() + m_inner.getRadii().topRight().height()), | 1186 edgeQuad[2].x(), |
1170 quad[2]); | 1187 edgeQuad[2].y() + m_inner.getRadii().topRight().height()), |
| 1188 edgeQuad[2]); |
| 1189 if (boundQuad1.y() < edgeQuad[2].y()) { |
| 1190 boundQuad1.setY(edgeQuad[2].y()); |
| 1191 boundQuad2.setY(edgeQuad[2].y()); |
| 1192 } |
1171 } | 1193 } |
1172 break; | 1194 break; |
1173 | 1195 |
1174 case BSLeft: | 1196 case BSLeft: |
1175 quad[0] = FloatPoint(outerRect.minXMinYCorner()); | 1197 // Swap the order of adjacent edges to allow common code |
1176 quad[1] = FloatPoint(innerRect.minXMinYCorner()); | 1198 std::swap(firstMiter, secondMiter); |
1177 quad[2] = FloatPoint(innerRect.minXMaxYCorner()); | 1199 edgeQuad[0] = FloatPoint(outerRect.minXMaxYCorner()); |
1178 quad[3] = FloatPoint(outerRect.minXMaxYCorner()); | 1200 edgeQuad[1] = FloatPoint(innerRect.minXMaxYCorner()); |
| 1201 edgeQuad[2] = FloatPoint(innerRect.minXMinYCorner()); |
| 1202 edgeQuad[3] = FloatPoint(outerRect.minXMinYCorner()); |
| 1203 |
| 1204 DCHECK(edgeQuad[0].x() == edgeQuad[3].x()); |
| 1205 DCHECK(edgeQuad[1].x() == edgeQuad[2].x()); |
| 1206 |
| 1207 boundQuad1 = FloatPoint(edgeQuad[1].x(), edgeQuad[0].y()); |
| 1208 boundQuad2 = FloatPoint(edgeQuad[2].x(), edgeQuad[3].y()); |
| 1209 |
| 1210 extensionOffset.setWidth(0); |
| 1211 extensionOffset.setHeight(kExtensionLength); |
1179 | 1212 |
1180 if (!m_inner.getRadii().topLeft().isZero()) { | 1213 if (!m_inner.getRadii().topLeft().isZero()) { |
1181 findIntersection( | 1214 findIntersection( |
1182 quad[0], quad[1], | 1215 edgeQuad[3], edgeQuad[2], |
1183 FloatPoint(quad[1].x() + m_inner.getRadii().topLeft().width(), | 1216 FloatPoint(edgeQuad[2].x() + m_inner.getRadii().topLeft().width(), |
1184 quad[1].y()), | 1217 edgeQuad[2].y()), |
1185 FloatPoint(quad[1].x(), | 1218 FloatPoint(edgeQuad[2].x(), |
1186 quad[1].y() + m_inner.getRadii().topLeft().height()), | 1219 edgeQuad[2].y() + m_inner.getRadii().topLeft().height()), |
1187 quad[1]); | 1220 edgeQuad[2]); |
| 1221 DCHECK(boundQuad2.x() <= edgeQuad[2].x()); |
| 1222 boundQuad1.setX(edgeQuad[2].x()); |
| 1223 boundQuad2.setX(edgeQuad[2].x()); |
1188 } | 1224 } |
1189 | 1225 |
1190 if (!m_inner.getRadii().bottomLeft().isZero()) { | 1226 if (!m_inner.getRadii().bottomLeft().isZero()) { |
1191 findIntersection( | 1227 findIntersection( |
1192 quad[3], quad[2], | 1228 edgeQuad[0], edgeQuad[1], |
1193 FloatPoint(quad[2].x() + m_inner.getRadii().bottomLeft().width(), | 1229 FloatPoint( |
1194 quad[2].y()), | 1230 edgeQuad[1].x() + m_inner.getRadii().bottomLeft().width(), |
1195 FloatPoint(quad[2].x(), | 1231 edgeQuad[1].y()), |
1196 quad[2].y() - m_inner.getRadii().bottomLeft().height()), | 1232 FloatPoint( |
1197 quad[2]); | 1233 edgeQuad[1].x(), |
| 1234 edgeQuad[1].y() - m_inner.getRadii().bottomLeft().height()), |
| 1235 edgeQuad[1]); |
| 1236 if (boundQuad1.x() < edgeQuad[1].x()) { |
| 1237 boundQuad1.setX(edgeQuad[1].x()); |
| 1238 boundQuad2.setX(edgeQuad[1].x()); |
| 1239 } |
1198 } | 1240 } |
1199 break; | 1241 break; |
1200 | 1242 |
1201 case BSBottom: | 1243 case BSBottom: |
1202 quad[0] = FloatPoint(outerRect.minXMaxYCorner()); | 1244 // Swap the order of adjacent edges to allow common code |
1203 quad[1] = FloatPoint(innerRect.minXMaxYCorner()); | 1245 std::swap(firstMiter, secondMiter); |
1204 quad[2] = FloatPoint(innerRect.maxXMaxYCorner()); | 1246 edgeQuad[0] = FloatPoint(outerRect.maxXMaxYCorner()); |
1205 quad[3] = FloatPoint(outerRect.maxXMaxYCorner()); | 1247 edgeQuad[1] = FloatPoint(innerRect.maxXMaxYCorner()); |
| 1248 edgeQuad[2] = FloatPoint(innerRect.minXMaxYCorner()); |
| 1249 edgeQuad[3] = FloatPoint(outerRect.minXMaxYCorner()); |
| 1250 |
| 1251 DCHECK(edgeQuad[0].y() == edgeQuad[3].y()); |
| 1252 DCHECK(edgeQuad[1].y() == edgeQuad[2].y()); |
| 1253 |
| 1254 boundQuad1 = FloatPoint(edgeQuad[0].x(), edgeQuad[1].y()); |
| 1255 boundQuad2 = FloatPoint(edgeQuad[3].x(), edgeQuad[2].y()); |
| 1256 |
| 1257 extensionOffset.setWidth(kExtensionLength); |
| 1258 extensionOffset.setHeight(0); |
1206 | 1259 |
1207 if (!m_inner.getRadii().bottomLeft().isZero()) { | 1260 if (!m_inner.getRadii().bottomLeft().isZero()) { |
1208 findIntersection( | 1261 findIntersection( |
1209 quad[0], quad[1], | 1262 edgeQuad[3], edgeQuad[2], |
1210 FloatPoint(quad[1].x() + m_inner.getRadii().bottomLeft().width(), | 1263 FloatPoint( |
1211 quad[1].y()), | 1264 edgeQuad[2].x() + m_inner.getRadii().bottomLeft().width(), |
1212 FloatPoint(quad[1].x(), | 1265 edgeQuad[2].y()), |
1213 quad[1].y() - m_inner.getRadii().bottomLeft().height()), | 1266 FloatPoint( |
1214 quad[1]); | 1267 edgeQuad[2].x(), |
| 1268 edgeQuad[2].y() - m_inner.getRadii().bottomLeft().height()), |
| 1269 edgeQuad[2]); |
| 1270 DCHECK(boundQuad2.y() >= edgeQuad[2].y()); |
| 1271 boundQuad1.setY(edgeQuad[2].y()); |
| 1272 boundQuad2.setY(edgeQuad[2].y()); |
1215 } | 1273 } |
1216 | 1274 |
1217 if (!m_inner.getRadii().bottomRight().isZero()) { | 1275 if (!m_inner.getRadii().bottomRight().isZero()) { |
1218 findIntersection( | 1276 findIntersection( |
1219 quad[3], quad[2], | 1277 edgeQuad[0], edgeQuad[1], |
1220 FloatPoint(quad[2].x() - m_inner.getRadii().bottomRight().width(), | 1278 FloatPoint( |
1221 quad[2].y()), | 1279 edgeQuad[1].x() - m_inner.getRadii().bottomRight().width(), |
1222 FloatPoint(quad[2].x(), | 1280 edgeQuad[1].y()), |
1223 quad[2].y() - m_inner.getRadii().bottomRight().height()), | 1281 FloatPoint( |
1224 quad[2]); | 1282 edgeQuad[1].x(), |
| 1283 edgeQuad[1].y() - m_inner.getRadii().bottomRight().height()), |
| 1284 edgeQuad[1]); |
| 1285 if (boundQuad1.y() > edgeQuad[1].y()) { |
| 1286 boundQuad1.setY(edgeQuad[1].y()); |
| 1287 boundQuad2.setY(edgeQuad[1].y()); |
| 1288 } |
1225 } | 1289 } |
1226 break; | 1290 break; |
1227 | 1291 |
1228 case BSRight: | 1292 case BSRight: |
1229 quad[0] = FloatPoint(outerRect.maxXMinYCorner()); | 1293 edgeQuad[0] = FloatPoint(outerRect.maxXMinYCorner()); |
1230 quad[1] = FloatPoint(innerRect.maxXMinYCorner()); | 1294 edgeQuad[1] = FloatPoint(innerRect.maxXMinYCorner()); |
1231 quad[2] = FloatPoint(innerRect.maxXMaxYCorner()); | 1295 edgeQuad[2] = FloatPoint(innerRect.maxXMaxYCorner()); |
1232 quad[3] = FloatPoint(outerRect.maxXMaxYCorner()); | 1296 edgeQuad[3] = FloatPoint(outerRect.maxXMaxYCorner()); |
| 1297 |
| 1298 DCHECK(edgeQuad[0].x() == edgeQuad[3].x()); |
| 1299 DCHECK(edgeQuad[1].x() == edgeQuad[2].x()); |
| 1300 |
| 1301 boundQuad1 = FloatPoint(edgeQuad[1].x(), edgeQuad[0].y()); |
| 1302 boundQuad2 = FloatPoint(edgeQuad[2].x(), edgeQuad[3].y()); |
| 1303 |
| 1304 extensionOffset.setWidth(0); |
| 1305 extensionOffset.setHeight(-kExtensionLength); |
1233 | 1306 |
1234 if (!m_inner.getRadii().topRight().isZero()) { | 1307 if (!m_inner.getRadii().topRight().isZero()) { |
1235 findIntersection( | 1308 findIntersection( |
1236 quad[0], quad[1], | 1309 edgeQuad[0], edgeQuad[1], |
1237 FloatPoint(quad[1].x() - m_inner.getRadii().topRight().width(), | 1310 FloatPoint(edgeQuad[1].x() - m_inner.getRadii().topRight().width(), |
1238 quad[1].y()), | 1311 edgeQuad[1].y()), |
1239 FloatPoint(quad[1].x(), | 1312 FloatPoint( |
1240 quad[1].y() + m_inner.getRadii().topRight().height()), | 1313 edgeQuad[1].x(), |
1241 quad[1]); | 1314 edgeQuad[1].y() + m_inner.getRadii().topRight().height()), |
| 1315 edgeQuad[1]); |
| 1316 DCHECK(boundQuad1.x() >= edgeQuad[1].x()); |
| 1317 boundQuad1.setX(edgeQuad[1].x()); |
| 1318 boundQuad2.setX(edgeQuad[1].x()); |
1242 } | 1319 } |
1243 | 1320 |
1244 if (!m_inner.getRadii().bottomRight().isZero()) { | 1321 if (!m_inner.getRadii().bottomRight().isZero()) { |
1245 findIntersection( | 1322 findIntersection( |
1246 quad[3], quad[2], | 1323 edgeQuad[3], edgeQuad[2], |
1247 FloatPoint(quad[2].x() - m_inner.getRadii().bottomRight().width(), | 1324 FloatPoint( |
1248 quad[2].y()), | 1325 edgeQuad[2].x() - m_inner.getRadii().bottomRight().width(), |
1249 FloatPoint(quad[2].x(), | 1326 edgeQuad[2].y()), |
1250 quad[2].y() - m_inner.getRadii().bottomRight().height()), | 1327 FloatPoint( |
1251 quad[2]); | 1328 edgeQuad[2].x(), |
| 1329 edgeQuad[2].y() - m_inner.getRadii().bottomRight().height()), |
| 1330 edgeQuad[2]); |
| 1331 if (boundQuad1.x() > edgeQuad[2].x()) { |
| 1332 boundQuad1.setX(edgeQuad[2].x()); |
| 1333 boundQuad2.setX(edgeQuad[2].x()); |
| 1334 } |
1252 } | 1335 } |
1253 break; | 1336 break; |
1254 } | 1337 } |
1255 | 1338 |
1256 if (firstMiter == secondMiter) { | 1339 if (firstMiter == secondMiter) { |
1257 clipQuad(graphicsContext, quad, firstMiter == SoftMiter); | 1340 clipQuad(graphicsContext, edgeQuad, firstMiter == SoftMiter); |
1258 return; | 1341 return; |
1259 } | 1342 } |
1260 | 1343 |
1261 // If antialiasing settings for the first edge and second edge is different, | 1344 // If antialiasing settings for the first edge and second edge are different, |
1262 // they have to be addressed separately. We do this by breaking the quad into | 1345 // they have to be addressed separately. We do this by applying 2 clips, one |
1263 // two parallelograms, made by moving quad[1] and quad[2]. | 1346 // for each miter, with the appropriate anti-aliasing setting. Each clip uses |
1264 float ax = quad[1].x() - quad[0].x(); | 1347 // 3 sides of the quad rectilinear bounding box and a 4th side aligned with |
1265 float ay = quad[1].y() - quad[0].y(); | 1348 // the miter edge. We extend the clip in the miter direction to ensure overlap |
1266 float bx = quad[2].x() - quad[1].x(); | 1349 // as each edge is drawn. |
1267 float by = quad[2].y() - quad[1].y(); | |
1268 float cx = quad[3].x() - quad[2].x(); | |
1269 float cy = quad[3].y() - quad[2].y(); | |
1270 | |
1271 const static float kEpsilon = 1e-2f; | |
1272 float r1, r2; | |
1273 if (fabsf(bx) < kEpsilon && fabsf(by) < kEpsilon) { | |
1274 // The quad was actually a triangle. | |
1275 r1 = r2 = 1.0f; | |
1276 } else { | |
1277 // Extend parallelogram a bit to hide calculation error | |
1278 const static float kExtendFill = 1e-2f; | |
1279 | |
1280 r1 = (-ax * by + ay * bx) / (cx * by - cy * bx) + kExtendFill; | |
1281 r2 = (-cx * by + cy * bx) / (ax * by - ay * bx) + kExtendFill; | |
1282 } | |
1283 | |
1284 if (firstMiter != NoMiter) { | 1350 if (firstMiter != NoMiter) { |
1285 FloatPoint firstQuad[4]; | 1351 FloatPoint clippingQuad[4]; |
1286 firstQuad[0] = quad[0]; | 1352 |
1287 firstQuad[1] = quad[1]; | 1353 clippingQuad[0] = edgeQuad[0] + extensionOffset; |
1288 firstQuad[2] = FloatPoint(quad[3].x() + r2 * ax, quad[3].y() + r2 * ay); | 1354 findIntersection(edgeQuad[0], edgeQuad[1], boundQuad1, boundQuad2, |
1289 firstQuad[3] = quad[3]; | 1355 clippingQuad[1]); |
1290 clipQuad(graphicsContext, firstQuad, firstMiter == SoftMiter); | 1356 clippingQuad[1] += extensionOffset; |
| 1357 clippingQuad[2] = boundQuad2; |
| 1358 clippingQuad[3] = edgeQuad[3]; |
| 1359 |
| 1360 clipQuad(graphicsContext, clippingQuad, firstMiter == SoftMiter); |
1291 } | 1361 } |
1292 | 1362 |
1293 if (secondMiter != NoMiter) { | 1363 if (secondMiter != NoMiter) { |
1294 FloatPoint secondQuad[4]; | 1364 FloatPoint clippingQuad[4]; |
1295 secondQuad[0] = quad[0]; | 1365 |
1296 secondQuad[1] = FloatPoint(quad[0].x() - r1 * cx, quad[0].y() - r1 * cy); | 1366 clippingQuad[0] = edgeQuad[0]; |
1297 secondQuad[2] = quad[2]; | 1367 clippingQuad[1] = boundQuad1; |
1298 secondQuad[3] = quad[3]; | 1368 findIntersection(edgeQuad[2], edgeQuad[3], boundQuad1, boundQuad2, |
1299 clipQuad(graphicsContext, secondQuad, secondMiter == SoftMiter); | 1369 clippingQuad[2]); |
| 1370 clippingQuad[2] -= extensionOffset; |
| 1371 clippingQuad[3] = edgeQuad[3] - extensionOffset; |
| 1372 |
| 1373 clipQuad(graphicsContext, clippingQuad, secondMiter == SoftMiter); |
1300 } | 1374 } |
1301 } | 1375 } |
1302 | 1376 |
1303 } // namespace blink | 1377 } // namespace blink |
OLD | NEW |