blob: 3c7e48db88e79b1eaad9c745800aee58f90de525 [file] [log] [blame]
/* libs/graphics/sgl/SkScan_AntiPath.cpp
**
** Copyright 2006, Google Inc.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#include "SkScanPriv.h"
#include "SkPath.h"
#include "SkMatrix.h"
#include "SkBlitter.h"
#include "SkRegion.h"
#include "SkAntiRun.h"
#define SHIFT 2
#define SCALE (1 << SHIFT)
#define MASK (SCALE - 1)
///////////////////////////////////////////////////////////////////////////////////////////
class SuperBlitter : public SkBlitter {
public:
SuperBlitter(SkBlitter* realBlitter, const SkRegion* clip, const SkRect16& ir);
virtual ~SuperBlitter()
{
sk_free(fRuns.fRuns);
}
void flush();
virtual void blitH(int x, int y, int width);
virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[])
{
SkASSERT(!"How did I get here?");
}
virtual void blitV(int x, int y, int height, SkAlpha alpha)
{
SkASSERT(!"How did I get here?");
}
virtual void blitRect(int x, int y, int width, int height)
{
SkASSERT(!"How did I get here?");
}
private:
SkBlitter* fRealBlitter;
int fCurrIY;
int fWidth, fLeft, fSuperLeft;
SkAlphaRuns fRuns;
SkDEBUGCODE(int fCurrX;)
SkDEBUGCODE(int fCurrY;)
};
SuperBlitter::SuperBlitter(SkBlitter* realBlitter, const SkRegion* clip, const SkRect16& ir)
{
fRealBlitter = realBlitter;
int width = ir.width();
// extra one to store the zero at the end
fRuns.fRuns = (S16*)sk_malloc_throw((width + 1 + (width + 2)/2) * sizeof(S16));
fRuns.fAlpha = (U8*)(fRuns.fRuns + width + 1);
fRuns.reset(width);
fLeft = ir.fLeft;
fSuperLeft = ir.fLeft << SHIFT;
fWidth = ir.width();
fCurrIY = -1;
SkDEBUGCODE(fCurrX = -1; fCurrY = -1;)
}
void SuperBlitter::flush()
{
if (fCurrIY >= 0)
{
if (!fRuns.empty())
{
// SkDEBUGCODE(fRuns.dump();)
fRealBlitter->blitAntiH(fLeft, fCurrIY, fRuns.fAlpha, fRuns.fRuns);
fRuns.reset(fWidth);
}
fCurrIY = -1;
SkDEBUGCODE(fCurrX = -1;)
}
}
static inline int coverage_to_alpha(int aa)
{
aa <<= 8 - 2*SHIFT;
aa -= aa >> (8 - SHIFT - 1);
return aa;
}
#define SUPER_Mask ((1 << SHIFT) - 1)
void SuperBlitter::blitH(int x, int y, int width)
{
int iy = y >> SHIFT;
SkASSERT(iy >= fCurrIY);
x -= fSuperLeft;
#if 0 // I should just need to assert
SkASSERT(x >= 0);
#else
// hack, until I figure out why my cubics (I think) go beyond the bounds
if (x < 0)
{
width += x;
x = 0;
}
#endif
#ifdef SK_DEBUG
SkASSERT(y >= fCurrY);
SkASSERT(y != fCurrY || x >= fCurrX);
fCurrY = y;
#endif
if (iy != fCurrIY) // new scanline
{
this->flush();
fCurrIY = iy;
}
// we sub 1 from maxValue 1 time for each block, so that we don't
// hit 256 as a summed max, but 255.
// int maxValue = (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT);
#if 0
SkAntiRun<SHIFT> arun;
arun.set(x, x + width);
fRuns.add(x >> SHIFT, arun.getStartAlpha(), arun.getMiddleCount(), arun.getStopAlpha(), maxValue);
#else
{
int start = x;
int stop = x + width;
SkASSERT(start >= 0 && stop > start);
int fb = start & SUPER_Mask;
int fe = stop & SUPER_Mask;
int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
if (n < 0)
{
fb = fe - fb;
n = 0;
fe = 0;
}
else
{
if (fb == 0)
n += 1;
else
fb = (1 << SHIFT) - fb;
}
fRuns.add(x >> SHIFT, coverage_to_alpha(fb), n, coverage_to_alpha(fe), (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT));
}
#endif
#ifdef SK_DEBUG
fRuns.assertValid(y & MASK, (1 << (8 - SHIFT)));
fCurrX = x + width;
#endif
}
//////////////////////////////////////////////////////////////////////////////////////////
static int overflows_short(int value)
{
return value - (short)value;
}
void SkScan::AntiFillPath(const SkPath& path, const SkRegion* clip, SkBlitter* blitter)
{
if (clip && clip->isEmpty())
return;
SkRect r;
SkRect16 ir;
path.computeBounds(&r, SkPath::kFast_BoundsType);
r.roundOut(&ir);
if (ir.isEmpty())
return;
if (overflows_short(ir.fLeft << SHIFT) ||
overflows_short(ir.fRight << SHIFT) ||
overflows_short(ir.width() << SHIFT) ||
overflows_short(ir.fTop << SHIFT) ||
overflows_short(ir.fBottom << SHIFT) ||
overflows_short(ir.height() << SHIFT))
return;
SkScanClipper clipper(blitter, clip, ir);
const SkRect16* clipRect = clipper.getClipRect();
blitter = clipper.getBlitter();
if (blitter == nil) // clipped out
return;
SuperBlitter superBlit(blitter, clip, ir);
SkRect16 superIR, superRect, *superClipRect = nil;
superIR.set(ir.fLeft << SHIFT, ir.fTop << SHIFT,
ir.fRight << SHIFT, ir.fBottom << SHIFT);
if (clipRect)
{
superRect.set( clipRect->fLeft << SHIFT, clipRect->fTop << SHIFT,
clipRect->fRight << SHIFT, clipRect->fBottom << SHIFT);
superClipRect = &superRect;
}
sk_fill_path(path, superClipRect, &superBlit, superIR, SHIFT);
superBlit.flush();
}