/* * Copyright 2006 The Android Open Source Project * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "include/core/SkPath.h" #include "include/core/SkRect.h" #include "include/core/SkRegion.h" #include "include/private/base/SkAssert.h" #include "include/private/base/SkMath.h" #include "src/core/SkAAClip.h" #include "src/core/SkBlitter.h" #include "src/core/SkRasterClip.h" #include "src/core/SkScan.h" #include "src/core/SkScanPriv.h" #include static SkIRect safeRoundOut(const SkRect& src) { // roundOut will pin huge floats to max/min int SkIRect dst = src.roundOut(); // intersect with a smaller huge rect, so the rect will not be considered empty for being // too large. e.g. { -SK_MaxS32 ... SK_MaxS32 } is considered empty because its width // exceeds signed 32bit. const int32_t limit = SK_MaxS32 >> SK_SUPERSAMPLE_SHIFT; (void)dst.intersect({ -limit, -limit, limit, limit}); return dst; } static int overflows_short_shift(int value, int shift) { const int s = 16 + shift; return (SkLeftShift(value, s) >> s) - value; } /** Would any of the coordinates of this rectangle not fit in a short, when left-shifted by shift? */ static int rect_overflows_short_shift(SkIRect rect, int shift) { SkASSERT(!overflows_short_shift(8191, shift)); SkASSERT(overflows_short_shift(8192, shift)); SkASSERT(!overflows_short_shift(32767, 0)); SkASSERT(overflows_short_shift(32768, 0)); // Since we expect these to succeed, we bit-or together // for a tiny extra bit of speed. return overflows_short_shift(rect.fLeft, shift) | overflows_short_shift(rect.fRight, shift) | overflows_short_shift(rect.fTop, shift) | overflows_short_shift(rect.fBottom, shift); } void SkScan::AntiFillPath(const SkPath& path, const SkRegion& origClip, SkBlitter* blitter, bool forceRLE) { if (origClip.isEmpty()) { return; } const bool isInverse = path.isInverseFillType(); SkIRect ir = safeRoundOut(path.getBounds()); if (ir.isEmpty()) { if (isInverse) { blitter->blitRegion(origClip); } return; } // If the intersection of the path bounds and the clip bounds // will overflow 32767 when << by SHIFT, we can't supersample, // so draw without antialiasing. SkIRect clippedIR; if (isInverse) { // If the path is an inverse fill, it's going to fill the entire // clip, and we care whether the entire clip exceeds our limits. clippedIR = origClip.getBounds(); } else { if (!clippedIR.intersect(ir, origClip.getBounds())) { return; } } if (rect_overflows_short_shift(clippedIR, SK_SUPERSAMPLE_SHIFT)) { SkScan::FillPath(path, origClip, blitter); return; } // Our antialiasing can't handle a clip larger than 32767, so we restrict // the clip to that limit here. (the runs[] uses int16_t for its index). // // A more general solution (one that could also eliminate the need to // disable aa based on ir bounds (see overflows_short_shift) would be // to tile the clip/target... SkRegion tmpClipStorage; const SkRegion* clipRgn = &origClip; { static const int32_t kMaxClipCoord = 32767; const SkIRect& bounds = origClip.getBounds(); if (bounds.fRight > kMaxClipCoord || bounds.fBottom > kMaxClipCoord) { SkIRect limit = { 0, 0, kMaxClipCoord, kMaxClipCoord }; tmpClipStorage.op(origClip, limit, SkRegion::kIntersect_Op); clipRgn = &tmpClipStorage; } } // for here down, use clipRgn, not origClip SkScanClipper clipper(blitter, clipRgn, ir); if (clipper.getBlitter() == nullptr) { // clipped out if (isInverse) { blitter->blitRegion(*clipRgn); } return; } SkASSERT(clipper.getClipRect() == nullptr || *clipper.getClipRect() == clipRgn->getBounds()); // now use the (possibly wrapped) blitter blitter = clipper.getBlitter(); if (isInverse) { sk_blit_above(blitter, ir, *clipRgn); } SkScan::AAAFillPath(path, blitter, ir, clipRgn->getBounds(), forceRLE); if (isInverse) { sk_blit_below(blitter, ir, *clipRgn); } } /////////////////////////////////////////////////////////////////////////////// void SkScan::FillPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* blitter) { if (clip.isEmpty() || !path.isFinite()) { return; } if (clip.isBW()) { FillPath(path, clip.bwRgn(), blitter); } else { SkRegion tmp; SkAAClipBlitter aaBlitter; tmp.setRect(clip.getBounds()); aaBlitter.init(blitter, &clip.aaRgn()); SkScan::FillPath(path, tmp, &aaBlitter); } } void SkScan::AntiFillPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* blitter) { if (clip.isEmpty() || !path.isFinite()) { return; } if (clip.isBW()) { AntiFillPath(path, clip.bwRgn(), blitter, false); } else { SkRegion tmp; SkAAClipBlitter aaBlitter; tmp.setRect(clip.getBounds()); aaBlitter.init(blitter, &clip.aaRgn()); AntiFillPath(path, tmp, &aaBlitter, true); // SkAAClipBlitter can blitMask, why forceRLE? } }