| OLD | NEW |
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2008 The Android Open Source Project | 3 * Copyright 2008 The Android Open Source Project |
| 4 * | 4 * |
| 5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
| 6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 | 9 |
| 10 #include "SkCanvas.h" | 10 #include "SkCanvas.h" |
| (...skipping 1148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1159 void SkCanvas::resetMatrix() { | 1159 void SkCanvas::resetMatrix() { |
| 1160 SkMatrix matrix; | 1160 SkMatrix matrix; |
| 1161 | 1161 |
| 1162 matrix.reset(); | 1162 matrix.reset(); |
| 1163 this->setMatrix(matrix); | 1163 this->setMatrix(matrix); |
| 1164 } | 1164 } |
| 1165 | 1165 |
| 1166 ////////////////////////////////////////////////////////////////////////////// | 1166 ////////////////////////////////////////////////////////////////////////////// |
| 1167 | 1167 |
| 1168 bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { | 1168 bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { |
| 1169 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; |
| 1170 this->onClipRect(rect, op, edgeStyle); |
| 1171 return !this->isClipEmpty(); |
| 1172 } |
| 1173 |
| 1174 void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edg
eStyle) { |
| 1169 #ifdef SK_ENABLE_CLIP_QUICKREJECT | 1175 #ifdef SK_ENABLE_CLIP_QUICKREJECT |
| 1170 if (SkRegion::kIntersect_Op == op) { | 1176 if (SkRegion::kIntersect_Op == op) { |
| 1171 if (fMCRec->fRasterClip->isEmpty()) { | 1177 if (fMCRec->fRasterClip->isEmpty()) { |
| 1172 return false; | 1178 return false; |
| 1173 } | 1179 } |
| 1174 | 1180 |
| 1175 if (this->quickReject(rect)) { | 1181 if (this->quickReject(rect)) { |
| 1176 fDeviceCMDirty = true; | 1182 fDeviceCMDirty = true; |
| 1177 fCachedLocalClipBoundsDirty = true; | 1183 fCachedLocalClipBoundsDirty = true; |
| 1178 | 1184 |
| 1179 fClipStack.clipEmpty(); | 1185 fClipStack.clipEmpty(); |
| 1180 return fMCRec->fRasterClip->setEmpty(); | 1186 return fMCRec->fRasterClip->setEmpty(); |
| 1181 } | 1187 } |
| 1182 } | 1188 } |
| 1183 #endif | 1189 #endif |
| 1184 | 1190 |
| 1185 AutoValidateClip avc(this); | 1191 AutoValidateClip avc(this); |
| 1186 | 1192 |
| 1187 fDeviceCMDirty = true; | 1193 fDeviceCMDirty = true; |
| 1188 fCachedLocalClipBoundsDirty = true; | 1194 fCachedLocalClipBoundsDirty = true; |
| 1189 doAA &= fAllowSoftClip; | 1195 if (!fAllowSoftClip) { |
| 1196 edgeStyle = kHard_ClipEdgeStyle; |
| 1197 } |
| 1190 | 1198 |
| 1191 if (fMCRec->fMatrix->rectStaysRect()) { | 1199 if (fMCRec->fMatrix->rectStaysRect()) { |
| 1192 // for these simpler matrices, we can stay a rect even after applying | 1200 // for these simpler matrices, we can stay a rect even after applying |
| 1193 // the matrix. This means we don't have to a) make a path, and b) tell | 1201 // the matrix. This means we don't have to a) make a path, and b) tell |
| 1194 // the region code to scan-convert the path, only to discover that it | 1202 // the region code to scan-convert the path, only to discover that it |
| 1195 // is really just a rect. | 1203 // is really just a rect. |
| 1196 SkRect r; | 1204 SkRect r; |
| 1197 | 1205 |
| 1198 fMCRec->fMatrix->mapRect(&r, rect); | 1206 fMCRec->fMatrix->mapRect(&r, rect); |
| 1199 fClipStack.clipDevRect(r, op, doAA); | 1207 fClipStack.clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle); |
| 1200 return fMCRec->fRasterClip->op(r, op, doAA); | 1208 fMCRec->fRasterClip->op(r, op, kSoft_ClipEdgeStyle == edgeStyle); |
| 1201 } else { | 1209 } else { |
| 1202 // since we're rotated or some such thing, we convert the rect to a path | 1210 // since we're rotated or some such thing, we convert the rect to a path |
| 1203 // and clip against that, since it can handle any matrix. However, to | 1211 // and clip against that, since it can handle any matrix. However, to |
| 1204 // avoid recursion in the case where we are subclassed (e.g. Pictures) | 1212 // avoid recursion in the case where we are subclassed (e.g. Pictures) |
| 1205 // we explicitly call "our" version of clipPath. | 1213 // we explicitly call "our" version of clipPath. |
| 1206 SkPath path; | 1214 SkPath path; |
| 1207 | 1215 |
| 1208 path.addRect(rect); | 1216 path.addRect(rect); |
| 1209 return this->SkCanvas::clipPath(path, op, doAA); | 1217 this->SkCanvas::onClipPath(path, op, edgeStyle); |
| 1210 } | 1218 } |
| 1211 } | 1219 } |
| 1212 | 1220 |
| 1213 static bool clipPathHelper(const SkCanvas* canvas, SkRasterClip* currClip, | 1221 static void clip_path_helper(const SkCanvas* canvas, SkRasterClip* currClip, |
| 1214 const SkPath& devPath, SkRegion::Op op, bool doAA) { | 1222 const SkPath& devPath, SkRegion::Op op, bool doAA)
{ |
| 1215 // base is used to limit the size (and therefore memory allocation) of the | 1223 // base is used to limit the size (and therefore memory allocation) of the |
| 1216 // region that results from scan converting devPath. | 1224 // region that results from scan converting devPath. |
| 1217 SkRegion base; | 1225 SkRegion base; |
| 1218 | 1226 |
| 1219 if (SkRegion::kIntersect_Op == op) { | 1227 if (SkRegion::kIntersect_Op == op) { |
| 1220 // since we are intersect, we can do better (tighter) with currRgn's | 1228 // since we are intersect, we can do better (tighter) with currRgn's |
| 1221 // bounds, than just using the device. However, if currRgn is complex, | 1229 // bounds, than just using the device. However, if currRgn is complex, |
| 1222 // our region blitter may hork, so we do that case in two steps. | 1230 // our region blitter may hork, so we do that case in two steps. |
| 1223 if (currClip->isRect()) { | 1231 if (currClip->isRect()) { |
| 1224 // FIXME: we should also be able to do this when currClip->isBW(), | 1232 // FIXME: we should also be able to do this when currClip->isBW(), |
| 1225 // but relaxing the test above triggers GM asserts in | 1233 // but relaxing the test above triggers GM asserts in |
| 1226 // SkRgnBuilder::blitH(). We need to investigate what's going on. | 1234 // SkRgnBuilder::blitH(). We need to investigate what's going on. |
| 1227 return currClip->setPath(devPath, currClip->bwRgn(), doAA); | 1235 currClip->setPath(devPath, currClip->bwRgn(), doAA); |
| 1228 } else { | 1236 } else { |
| 1229 base.setRect(currClip->getBounds()); | 1237 base.setRect(currClip->getBounds()); |
| 1230 SkRasterClip clip; | 1238 SkRasterClip clip; |
| 1231 clip.setPath(devPath, base, doAA); | 1239 clip.setPath(devPath, base, doAA); |
| 1232 return currClip->op(clip, op); | 1240 currClip->op(clip, op); |
| 1233 } | 1241 } |
| 1234 } else { | 1242 } else { |
| 1235 const SkBaseDevice* device = canvas->getDevice(); | 1243 const SkBaseDevice* device = canvas->getDevice(); |
| 1236 if (!device) { | 1244 if (!device) { |
| 1237 return currClip->setEmpty(); | 1245 currClip->setEmpty(); |
| 1246 return; |
| 1238 } | 1247 } |
| 1239 | 1248 |
| 1240 base.setRect(0, 0, device->width(), device->height()); | 1249 base.setRect(0, 0, device->width(), device->height()); |
| 1241 | 1250 |
| 1242 if (SkRegion::kReplace_Op == op) { | 1251 if (SkRegion::kReplace_Op == op) { |
| 1243 return currClip->setPath(devPath, base, doAA); | 1252 currClip->setPath(devPath, base, doAA); |
| 1244 } else { | 1253 } else { |
| 1245 SkRasterClip clip; | 1254 SkRasterClip clip; |
| 1246 clip.setPath(devPath, base, doAA); | 1255 clip.setPath(devPath, base, doAA); |
| 1247 return currClip->op(clip, op); | 1256 currClip->op(clip, op); |
| 1248 } | 1257 } |
| 1249 } | 1258 } |
| 1250 } | 1259 } |
| 1251 | 1260 |
| 1252 bool SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { | 1261 bool SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { |
| 1262 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; |
| 1253 if (rrect.isRect()) { | 1263 if (rrect.isRect()) { |
| 1254 // call the non-virtual version | 1264 this->onClipRect(rrect.getBounds(), op, edgeStyle); |
| 1255 return this->SkCanvas::clipRect(rrect.getBounds(), op, doAA); | 1265 } else { |
| 1266 this->onClipRRect(rrect, op, edgeStyle); |
| 1256 } | 1267 } |
| 1268 return !this->isClipEmpty(); |
| 1269 } |
| 1257 | 1270 |
| 1271 void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle
edgeStyle) { |
| 1258 SkRRect transformedRRect; | 1272 SkRRect transformedRRect; |
| 1259 if (rrect.transform(*fMCRec->fMatrix, &transformedRRect)) { | 1273 if (rrect.transform(*fMCRec->fMatrix, &transformedRRect)) { |
| 1260 AutoValidateClip avc(this); | 1274 AutoValidateClip avc(this); |
| 1261 | 1275 |
| 1262 fDeviceCMDirty = true; | 1276 fDeviceCMDirty = true; |
| 1263 fCachedLocalClipBoundsDirty = true; | 1277 fCachedLocalClipBoundsDirty = true; |
| 1264 doAA &= fAllowSoftClip; | 1278 if (!fAllowSoftClip) { |
| 1279 edgeStyle = kHard_ClipEdgeStyle; |
| 1280 } |
| 1265 | 1281 |
| 1266 fClipStack.clipDevRRect(transformedRRect, op, doAA); | 1282 fClipStack.clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edg
eStyle); |
| 1267 | 1283 |
| 1268 SkPath devPath; | 1284 SkPath devPath; |
| 1269 devPath.addRRect(transformedRRect); | 1285 devPath.addRRect(transformedRRect); |
| 1270 | 1286 |
| 1271 return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA); | 1287 clip_path_helper(this, fMCRec->fRasterClip, devPath, op, kSoft_ClipEdgeS
tyle == edgeStyle); |
| 1288 return; |
| 1272 } | 1289 } |
| 1273 | 1290 |
| 1274 SkPath path; | 1291 SkPath path; |
| 1275 path.addRRect(rrect); | 1292 path.addRRect(rrect); |
| 1276 // call the non-virtual version | 1293 // call the non-virtual version |
| 1277 return this->SkCanvas::clipPath(path, op, doAA); | 1294 this->SkCanvas::onClipPath(path, op, edgeStyle); |
| 1278 } | 1295 } |
| 1279 | 1296 |
| 1280 bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { | 1297 bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { |
| 1298 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; |
| 1299 SkRect r; |
| 1300 if (!path.isInverseFillType() && path.isRect(&r)) { |
| 1301 this->onClipRect(r, op, edgeStyle); |
| 1302 } else { |
| 1303 this->onClipPath(path, op, edgeStyle); |
| 1304 } |
| 1305 |
| 1306 return !this->isClipEmpty(); |
| 1307 } |
| 1308 |
| 1309 void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edg
eStyle) { |
| 1281 #ifdef SK_ENABLE_CLIP_QUICKREJECT | 1310 #ifdef SK_ENABLE_CLIP_QUICKREJECT |
| 1282 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) { | 1311 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) { |
| 1283 if (fMCRec->fRasterClip->isEmpty()) { | 1312 if (fMCRec->fRasterClip->isEmpty()) { |
| 1284 return false; | 1313 return false; |
| 1285 } | 1314 } |
| 1286 | 1315 |
| 1287 if (this->quickReject(path.getBounds())) { | 1316 if (this->quickReject(path.getBounds())) { |
| 1288 fDeviceCMDirty = true; | 1317 fDeviceCMDirty = true; |
| 1289 fCachedLocalClipBoundsDirty = true; | 1318 fCachedLocalClipBoundsDirty = true; |
| 1290 | 1319 |
| 1291 fClipStack.clipEmpty(); | 1320 fClipStack.clipEmpty(); |
| 1292 return fMCRec->fRasterClip->setEmpty(); | 1321 return fMCRec->fRasterClip->setEmpty(); |
| 1293 } | 1322 } |
| 1294 } | 1323 } |
| 1295 #endif | 1324 #endif |
| 1296 | 1325 |
| 1297 AutoValidateClip avc(this); | 1326 AutoValidateClip avc(this); |
| 1298 | 1327 |
| 1299 fDeviceCMDirty = true; | 1328 fDeviceCMDirty = true; |
| 1300 fCachedLocalClipBoundsDirty = true; | 1329 fCachedLocalClipBoundsDirty = true; |
| 1301 doAA &= fAllowSoftClip; | 1330 if (!fAllowSoftClip) { |
| 1331 edgeStyle = kHard_ClipEdgeStyle; |
| 1332 } |
| 1302 | 1333 |
| 1303 SkPath devPath; | 1334 SkPath devPath; |
| 1304 path.transform(*fMCRec->fMatrix, &devPath); | 1335 path.transform(*fMCRec->fMatrix, &devPath); |
| 1305 | 1336 |
| 1306 // Check if the transfomation, or the original path itself | 1337 // Check if the transfomation, or the original path itself |
| 1307 // made us empty. Note this can also happen if we contained NaN | 1338 // made us empty. Note this can also happen if we contained NaN |
| 1308 // values. computing the bounds detects this, and will set our | 1339 // values. computing the bounds detects this, and will set our |
| 1309 // bounds to empty if that is the case. (see SkRect::set(pts, count)) | 1340 // bounds to empty if that is the case. (see SkRect::set(pts, count)) |
| 1310 if (devPath.getBounds().isEmpty()) { | 1341 if (devPath.getBounds().isEmpty()) { |
| 1311 // resetting the path will remove any NaN or other wanky values | 1342 // resetting the path will remove any NaN or other wanky values |
| 1312 // that might upset our scan converter. | 1343 // that might upset our scan converter. |
| 1313 devPath.reset(); | 1344 devPath.reset(); |
| 1314 } | 1345 } |
| 1315 | 1346 |
| 1316 // if we called path.swap() we could avoid a deep copy of this path | 1347 // if we called path.swap() we could avoid a deep copy of this path |
| 1317 fClipStack.clipDevPath(devPath, op, doAA); | 1348 fClipStack.clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle); |
| 1318 | 1349 |
| 1319 if (fAllowSimplifyClip) { | 1350 if (fAllowSimplifyClip) { |
| 1320 devPath.reset(); | 1351 devPath.reset(); |
| 1321 devPath.setFillType(SkPath::kInverseEvenOdd_FillType); | 1352 devPath.setFillType(SkPath::kInverseEvenOdd_FillType); |
| 1322 const SkClipStack* clipStack = getClipStack(); | 1353 const SkClipStack* clipStack = getClipStack(); |
| 1323 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart)
; | 1354 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart)
; |
| 1324 const SkClipStack::Element* element; | 1355 const SkClipStack::Element* element; |
| 1325 while ((element = iter.next())) { | 1356 while ((element = iter.next())) { |
| 1326 SkClipStack::Element::Type type = element->getType(); | 1357 SkClipStack::Element::Type type = element->getType(); |
| 1327 if (type == SkClipStack::Element::kEmpty_Type) { | 1358 if (type == SkClipStack::Element::kEmpty_Type) { |
| 1328 continue; | 1359 continue; |
| 1329 } | 1360 } |
| 1330 SkPath operand; | 1361 SkPath operand; |
| 1331 element->asPath(&operand); | 1362 element->asPath(&operand); |
| 1332 SkRegion::Op elementOp = element->getOp(); | 1363 SkRegion::Op elementOp = element->getOp(); |
| 1333 if (elementOp == SkRegion::kReplace_Op) { | 1364 if (elementOp == SkRegion::kReplace_Op) { |
| 1334 devPath = operand; | 1365 devPath = operand; |
| 1335 } else { | 1366 } else { |
| 1336 Op(devPath, operand, (SkPathOp) elementOp, &devPath); | 1367 Op(devPath, operand, (SkPathOp) elementOp, &devPath); |
| 1337 } | 1368 } |
| 1338 // if the prev and curr clips disagree about aa -vs- not, favor the
aa request. | 1369 // if the prev and curr clips disagree about aa -vs- not, favor the
aa request. |
| 1339 // perhaps we need an API change to avoid this sort of mixed-signals
about | 1370 // perhaps we need an API change to avoid this sort of mixed-signals
about |
| 1340 // clipping. | 1371 // clipping. |
| 1341 doAA |= element->isAA(); | 1372 if (element->isAA()) { |
| 1373 edgeStyle = kSoft_ClipEdgeStyle; |
| 1374 } |
| 1342 } | 1375 } |
| 1343 op = SkRegion::kReplace_Op; | 1376 op = SkRegion::kReplace_Op; |
| 1344 } | 1377 } |
| 1345 | 1378 |
| 1346 return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA); | 1379 clip_path_helper(this, fMCRec->fRasterClip, devPath, op, edgeStyle); |
| 1347 } | 1380 } |
| 1348 | 1381 |
| 1349 bool SkCanvas::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegio
n::Op op, | 1382 bool SkCanvas::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegio
n::Op op, |
| 1350 bool inverseFilled) { | 1383 bool inverseFilled) { |
| 1351 // This is for updating the clip conservatively using only bounds | 1384 // This is for updating the clip conservatively using only bounds |
| 1352 // information. | 1385 // information. |
| 1353 // Contract: | 1386 // Contract: |
| 1354 // The current clip must contain the true clip. The true | 1387 // The current clip must contain the true clip. The true |
| 1355 // clip is the clip that would have normally been computed | 1388 // clip is the clip that would have normally been computed |
| 1356 // by calls to clipPath and clipRRect | 1389 // by calls to clipPath and clipRRect |
| 1357 // Objective: | 1390 // Objective: |
| 1358 // Keep the current clip as small as possible without | 1391 // Keep the current clip as small as possible without |
| 1359 // breaking the contract, using only clip bounding rectangles | 1392 // breaking the contract, using only clip bounding rectangles |
| 1360 // (for performance). | 1393 // (for performance). |
| 1361 | 1394 |
| 1362 // N.B.: This *never* calls back through a virtual on canvas, so subclasses | 1395 // N.B.: This *never* calls back through a virtual on canvas, so subclasses |
| 1363 // don't have to worry about getting caught in a loop. Thus anywhere | 1396 // don't have to worry about getting caught in a loop. Thus anywhere |
| 1364 // we call a virtual method, we explicitly prefix it with | 1397 // we call a virtual method, we explicitly prefix it with |
| 1365 // SkCanvas:: to be sure to call the base-class. | 1398 // SkCanvas:: to be sure to call the base-class. |
| 1366 | 1399 |
| 1367 if (inverseFilled) { | 1400 if (inverseFilled) { |
| 1368 switch (op) { | 1401 switch (op) { |
| 1369 case SkRegion::kIntersect_Op: | 1402 case SkRegion::kIntersect_Op: |
| 1370 case SkRegion::kDifference_Op: | 1403 case SkRegion::kDifference_Op: |
| 1371 // These ops can only shrink the current clip. So leaving | 1404 // These ops can only shrink the current clip. So leaving |
| 1372 // the clip unchanges conservatively respects the contract. | 1405 // the clip unchanged conservatively respects the contract. |
| 1373 return this->getClipDeviceBounds(NULL); | 1406 break; |
| 1374 case SkRegion::kUnion_Op: | 1407 case SkRegion::kUnion_Op: |
| 1375 case SkRegion::kReplace_Op: | 1408 case SkRegion::kReplace_Op: |
| 1376 case SkRegion::kReverseDifference_Op: | 1409 case SkRegion::kReverseDifference_Op: |
| 1377 case SkRegion::kXOR_Op: | 1410 case SkRegion::kXOR_Op: { |
| 1378 { | |
| 1379 // These ops can grow the current clip up to the extents of | 1411 // These ops can grow the current clip up to the extents of |
| 1380 // the input clip, which is inverse filled, so we just set | 1412 // the input clip, which is inverse filled, so we just set |
| 1381 // the current clip to the device bounds. | 1413 // the current clip to the device bounds. |
| 1382 SkRect deviceBounds; | 1414 SkRect deviceBounds; |
| 1383 SkIRect deviceIBounds; | 1415 SkIRect deviceIBounds; |
| 1384 this->getDevice()->getGlobalBounds(&deviceIBounds); | 1416 this->getDevice()->getGlobalBounds(&deviceIBounds); |
| 1385 deviceBounds = SkRect::Make(deviceIBounds); | 1417 deviceBounds = SkRect::Make(deviceIBounds); |
| 1386 this->SkCanvas::save(SkCanvas::kMatrix_SaveFlag); | 1418 this->SkCanvas::save(SkCanvas::kMatrix_SaveFlag); |
| 1387 // set the clip in device space | 1419 // set the clip in device space |
| 1388 this->SkCanvas::setMatrix(SkMatrix::I()); | 1420 this->SkCanvas::setMatrix(SkMatrix::I()); |
| 1389 bool result = this->SkCanvas::clipRect(deviceBounds, | 1421 this->SkCanvas::onClipRect(deviceBounds, SkRegion::kReplace_
Op, |
| 1390 SkRegion::kReplace_Op, false); | 1422 kHard_ClipEdgeStyle); |
| 1391 this->SkCanvas::restore(); //pop the matrix, but keep the cl
ip | 1423 this->SkCanvas::restore(); //pop the matrix, but keep the cl
ip |
| 1392 return result; | 1424 break; |
| 1393 } | 1425 } |
| 1394 default: | 1426 default: |
| 1395 SkASSERT(0); // unhandled op? | 1427 SkASSERT(0); // unhandled op? |
| 1396 } | 1428 } |
| 1397 } else { | 1429 } else { |
| 1398 // Not inverse filled | 1430 // Not inverse filled |
| 1399 switch (op) { | 1431 switch (op) { |
| 1400 case SkRegion::kIntersect_Op: | 1432 case SkRegion::kIntersect_Op: |
| 1401 case SkRegion::kUnion_Op: | 1433 case SkRegion::kUnion_Op: |
| 1402 case SkRegion::kReplace_Op: | 1434 case SkRegion::kReplace_Op: |
| 1403 return this->SkCanvas::clipRect(bounds, op, false); | 1435 this->SkCanvas::onClipRect(bounds, op, kHard_ClipEdgeStyle); |
| 1436 break; |
| 1404 case SkRegion::kDifference_Op: | 1437 case SkRegion::kDifference_Op: |
| 1405 // Difference can only shrink the current clip. | 1438 // Difference can only shrink the current clip. |
| 1406 // Leaving clip unchanged conservatively fullfills the contract. | 1439 // Leaving clip unchanged conservatively fullfills the contract. |
| 1407 return this->getClipDeviceBounds(NULL); | 1440 break; |
| 1408 case SkRegion::kReverseDifference_Op: | 1441 case SkRegion::kReverseDifference_Op: |
| 1409 // To reverse, we swap in the bounds with a replace op. | 1442 // To reverse, we swap in the bounds with a replace op. |
| 1410 // As with difference, leave it unchanged. | 1443 // As with difference, leave it unchanged. |
| 1411 return this->SkCanvas::clipRect(bounds, SkRegion::kReplace_Op, f
alse); | 1444 this->SkCanvas::onClipRect(bounds, SkRegion::kReplace_Op, kHard_
ClipEdgeStyle); |
| 1445 break; |
| 1412 case SkRegion::kXOR_Op: | 1446 case SkRegion::kXOR_Op: |
| 1413 // Be conservative, based on (A XOR B) always included in (A uni
on B), | 1447 // Be conservative, based on (A XOR B) always included in (A uni
on B), |
| 1414 // which is always included in (bounds(A) union bounds(B)) | 1448 // which is always included in (bounds(A) union bounds(B)) |
| 1415 return this->SkCanvas::clipRect(bounds, SkRegion::kUnion_Op, fal
se); | 1449 this->SkCanvas::onClipRect(bounds, SkRegion::kUnion_Op, kHard_Cl
ipEdgeStyle); |
| 1450 break; |
| 1416 default: | 1451 default: |
| 1417 SkASSERT(0); // unhandled op? | 1452 SkASSERT(0); // unhandled op? |
| 1418 } | 1453 } |
| 1419 } | 1454 } |
| 1420 return true; | 1455 |
| 1456 return !this->isClipEmpty(); |
| 1421 } | 1457 } |
| 1422 | 1458 |
| 1423 bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { | 1459 bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { |
| 1460 this->onClipRegion(rgn, op); |
| 1461 return !this->isClipEmpty(); |
| 1462 } |
| 1463 |
| 1464 void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) { |
| 1424 AutoValidateClip avc(this); | 1465 AutoValidateClip avc(this); |
| 1425 | 1466 |
| 1426 fDeviceCMDirty = true; | 1467 fDeviceCMDirty = true; |
| 1427 fCachedLocalClipBoundsDirty = true; | 1468 fCachedLocalClipBoundsDirty = true; |
| 1428 | 1469 |
| 1429 // todo: signal fClipStack that we have a region, and therefore (I guess) | 1470 // todo: signal fClipStack that we have a region, and therefore (I guess) |
| 1430 // we have to ignore it, and use the region directly? | 1471 // we have to ignore it, and use the region directly? |
| 1431 fClipStack.clipDevRect(rgn.getBounds(), op); | 1472 fClipStack.clipDevRect(rgn.getBounds(), op); |
| 1432 | 1473 |
| 1433 return fMCRec->fRasterClip->op(rgn, op); | 1474 fMCRec->fRasterClip->op(rgn, op); |
| 1434 } | 1475 } |
| 1435 | 1476 |
| 1436 #ifdef SK_DEBUG | 1477 #ifdef SK_DEBUG |
| 1437 void SkCanvas::validateClip() const { | 1478 void SkCanvas::validateClip() const { |
| 1438 // construct clipRgn from the clipstack | 1479 // construct clipRgn from the clipstack |
| 1439 const SkBaseDevice* device = this->getDevice(); | 1480 const SkBaseDevice* device = this->getDevice(); |
| 1440 if (!device) { | 1481 if (!device) { |
| 1441 SkASSERT(this->getTotalClip().isEmpty()); | 1482 SkASSERT(this->getTotalClip().isEmpty()); |
| 1442 return; | 1483 return; |
| 1443 } | 1484 } |
| 1444 | 1485 |
| 1445 SkIRect ir; | 1486 SkIRect ir; |
| 1446 ir.set(0, 0, device->width(), device->height()); | 1487 ir.set(0, 0, device->width(), device->height()); |
| 1447 SkRasterClip tmpClip(ir); | 1488 SkRasterClip tmpClip(ir); |
| 1448 | 1489 |
| 1449 SkClipStack::B2TIter iter(fClipStack); | 1490 SkClipStack::B2TIter iter(fClipStack); |
| 1450 const SkClipStack::Element* element; | 1491 const SkClipStack::Element* element; |
| 1451 while ((element = iter.next()) != NULL) { | 1492 while ((element = iter.next()) != NULL) { |
| 1452 switch (element->getType()) { | 1493 switch (element->getType()) { |
| 1453 case SkClipStack::Element::kRect_Type: | 1494 case SkClipStack::Element::kRect_Type: |
| 1454 element->getRect().round(&ir); | 1495 element->getRect().round(&ir); |
| 1455 tmpClip.op(ir, element->getOp()); | 1496 tmpClip.op(ir, element->getOp()); |
| 1456 break; | 1497 break; |
| 1457 case SkClipStack::Element::kEmpty_Type: | 1498 case SkClipStack::Element::kEmpty_Type: |
| 1458 tmpClip.setEmpty(); | 1499 tmpClip.setEmpty(); |
| 1459 break; | 1500 break; |
| 1460 default: { | 1501 default: { |
| 1461 SkPath path; | 1502 SkPath path; |
| 1462 element->asPath(&path); | 1503 element->asPath(&path); |
| 1463 clipPathHelper(this, | 1504 clip_path_helper(this, &tmpClip, path, element->getOp(), element
->isAA()); |
| 1464 &tmpClip, | |
| 1465 path, | |
| 1466 element->getOp(), | |
| 1467 element->isAA()); | |
| 1468 break; | 1505 break; |
| 1469 } | 1506 } |
| 1470 } | 1507 } |
| 1471 } | 1508 } |
| 1472 | 1509 |
| 1473 #if 0 // enable this locally for testing | 1510 #if 0 // enable this locally for testing |
| 1474 // now compare against the current rgn | 1511 // now compare against the current rgn |
| 1475 const SkRegion& rgn = this->getTotalClip(); | 1512 const SkRegion& rgn = this->getTotalClip(); |
| 1476 SkASSERT(rgn == tmpClip); | 1513 SkASSERT(rgn == tmpClip); |
| 1477 #endif | 1514 #endif |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1536 return false; | 1573 return false; |
| 1537 } | 1574 } |
| 1538 } | 1575 } |
| 1539 | 1576 |
| 1540 bool SkCanvas::quickReject(const SkPath& path) const { | 1577 bool SkCanvas::quickReject(const SkPath& path) const { |
| 1541 return path.isEmpty() || this->quickReject(path.getBounds()); | 1578 return path.isEmpty() || this->quickReject(path.getBounds()); |
| 1542 } | 1579 } |
| 1543 | 1580 |
| 1544 bool SkCanvas::getClipBounds(SkRect* bounds) const { | 1581 bool SkCanvas::getClipBounds(SkRect* bounds) const { |
| 1545 SkIRect ibounds; | 1582 SkIRect ibounds; |
| 1546 if (!getClipDeviceBounds(&ibounds)) { | 1583 if (!this->getClipDeviceBounds(&ibounds)) { |
| 1547 return false; | 1584 return false; |
| 1548 } | 1585 } |
| 1549 | 1586 |
| 1550 SkMatrix inverse; | 1587 SkMatrix inverse; |
| 1551 // if we can't invert the CTM, we can't return local clip bounds | 1588 // if we can't invert the CTM, we can't return local clip bounds |
| 1552 if (!fMCRec->fMatrix->invert(&inverse)) { | 1589 if (!fMCRec->fMatrix->invert(&inverse)) { |
| 1553 if (bounds) { | 1590 if (bounds) { |
| 1554 bounds->setEmpty(); | 1591 bounds->setEmpty(); |
| 1555 } | 1592 } |
| 1556 return false; | 1593 return false; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1581 *bounds = clip.getBounds(); | 1618 *bounds = clip.getBounds(); |
| 1582 } | 1619 } |
| 1583 return true; | 1620 return true; |
| 1584 } | 1621 } |
| 1585 | 1622 |
| 1586 const SkMatrix& SkCanvas::getTotalMatrix() const { | 1623 const SkMatrix& SkCanvas::getTotalMatrix() const { |
| 1587 return *fMCRec->fMatrix; | 1624 return *fMCRec->fMatrix; |
| 1588 } | 1625 } |
| 1589 | 1626 |
| 1590 SkCanvas::ClipType SkCanvas::getClipType() const { | 1627 SkCanvas::ClipType SkCanvas::getClipType() const { |
| 1591 if (fMCRec->fRasterClip->isEmpty()) return kEmpty_ClipType; | 1628 if (fMCRec->fRasterClip->isEmpty()) { |
| 1592 if (fMCRec->fRasterClip->isRect()) return kRect_ClipType; | 1629 return kEmpty_ClipType; |
| 1630 } |
| 1631 if (fMCRec->fRasterClip->isRect()) { |
| 1632 return kRect_ClipType; |
| 1633 } |
| 1593 return kComplex_ClipType; | 1634 return kComplex_ClipType; |
| 1594 } | 1635 } |
| 1595 | 1636 |
| 1596 const SkRegion& SkCanvas::getTotalClip() const { | 1637 const SkRegion& SkCanvas::getTotalClip() const { |
| 1597 return fMCRec->fRasterClip->forceGetBW(); | 1638 return fMCRec->fRasterClip->forceGetBW(); |
| 1598 } | 1639 } |
| 1599 | 1640 |
| 1600 SkBaseDevice* SkCanvas::createLayerDevice(const SkImageInfo& info) { | 1641 SkBaseDevice* SkCanvas::createLayerDevice(const SkImageInfo& info) { |
| 1601 SkBaseDevice* device = this->getTopDevice(); | 1642 SkBaseDevice* device = this->getTopDevice(); |
| 1602 return device ? device->createCompatibleDeviceForSaveLayer(info) : NULL; | 1643 return device ? device->createCompatibleDeviceForSaveLayer(info) : NULL; |
| (...skipping 744 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2347 if (!bitmap.allocPixels(info)) { | 2388 if (!bitmap.allocPixels(info)) { |
| 2348 return NULL; | 2389 return NULL; |
| 2349 } | 2390 } |
| 2350 | 2391 |
| 2351 // should this functionality be moved into allocPixels()? | 2392 // should this functionality be moved into allocPixels()? |
| 2352 if (!bitmap.info().isOpaque()) { | 2393 if (!bitmap.info().isOpaque()) { |
| 2353 bitmap.eraseColor(0); | 2394 bitmap.eraseColor(0); |
| 2354 } | 2395 } |
| 2355 return SkNEW_ARGS(SkCanvas, (bitmap)); | 2396 return SkNEW_ARGS(SkCanvas, (bitmap)); |
| 2356 } | 2397 } |
| OLD | NEW |