mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-12 02:31:41 +00:00
Bug 1457284 - add Skia m66 cherry-picks. r=rhunt
MozReview-Commit-ID: 4naJirEFhiV
This commit is contained in:
parent
f55bef228c
commit
f27dc02d63
@ -64,7 +64,6 @@ UNIFIED_SOURCES += [
|
||||
'skia/src/core/SkDeferredDisplayListRecorder.cpp',
|
||||
'skia/src/core/SkDeque.cpp',
|
||||
'skia/src/core/SkDevice.cpp',
|
||||
'skia/src/core/SkDeviceLooper.cpp',
|
||||
'skia/src/core/SkDeviceProfile.cpp',
|
||||
'skia/src/core/SkDistanceFieldGen.cpp',
|
||||
'skia/src/core/SkDither.cpp',
|
||||
|
@ -23,6 +23,116 @@
|
||||
#include "SkTLazy.h"
|
||||
#include "SkVertices.h"
|
||||
|
||||
class SkDrawTiler {
|
||||
enum {
|
||||
// 8K is 1 too big, since 8K << supersample == 32768 which is too big for SkFixed
|
||||
kMaxDim = 8192 - 1
|
||||
};
|
||||
|
||||
SkBitmapDevice* fDevice;
|
||||
SkPixmap fRootPixmap;
|
||||
|
||||
// Used for tiling and non-tiling
|
||||
SkDraw fDraw;
|
||||
|
||||
// fCurr... are only used if fNeedTiling
|
||||
SkMatrix fTileMatrix;
|
||||
SkRasterClip fTileRC;
|
||||
SkIPoint fCurrOrigin, fOrigin;
|
||||
|
||||
bool fDone, fNeedsTiling;
|
||||
|
||||
public:
|
||||
SkDrawTiler(SkBitmapDevice* dev) : fDevice(dev) {
|
||||
// we need fDst to be set, and if we're actually drawing, to dirty the genID
|
||||
if (!dev->accessPixels(&fRootPixmap)) {
|
||||
// NoDrawDevice uses us (why?) so we have to catch this case w/ no pixels
|
||||
fRootPixmap.reset(dev->imageInfo(), nullptr, 0);
|
||||
}
|
||||
|
||||
fDone = false;
|
||||
fNeedsTiling = fRootPixmap.width() > kMaxDim || fRootPixmap.height() > kMaxDim;
|
||||
fOrigin.set(0, 0);
|
||||
fCurrOrigin = fOrigin;
|
||||
|
||||
if (fNeedsTiling) {
|
||||
// fDraw.fDst is reset each time in setupTileDraw()
|
||||
fDraw.fMatrix = &fTileMatrix;
|
||||
fDraw.fRC = &fTileRC;
|
||||
} else {
|
||||
fDraw.fDst = fRootPixmap;
|
||||
fDraw.fMatrix = &dev->ctm();
|
||||
fDraw.fRC = &dev->fRCStack.rc();
|
||||
}
|
||||
}
|
||||
|
||||
bool needsTiling() const { return fNeedsTiling; }
|
||||
|
||||
const SkDraw* next() {
|
||||
if (fDone) {
|
||||
return nullptr;
|
||||
}
|
||||
if (fNeedsTiling) {
|
||||
do {
|
||||
this->setupTileDraw(); // might set the clip to empty
|
||||
this->stepOrigin(); // might set fDone to true
|
||||
} while (!fDone && fTileRC.isEmpty());
|
||||
// if we exit the loop and we're still empty, we're (past) done
|
||||
if (fTileRC.isEmpty()) {
|
||||
SkASSERT(fDone);
|
||||
return nullptr;
|
||||
}
|
||||
SkASSERT(!fTileRC.isEmpty());
|
||||
} else {
|
||||
fDone = true; // only draw untiled once
|
||||
}
|
||||
return &fDraw;
|
||||
}
|
||||
|
||||
int curr_x() const { return fCurrOrigin.x(); }
|
||||
int curr_y() const { return fCurrOrigin.y(); }
|
||||
|
||||
private:
|
||||
void setupTileDraw() {
|
||||
SkASSERT(!fDone);
|
||||
SkIRect bounds = SkIRect::MakeXYWH(fOrigin.x(), fOrigin.y(), kMaxDim, kMaxDim);
|
||||
SkASSERT(!bounds.isEmpty());
|
||||
bool success = fRootPixmap.extractSubset(&fDraw.fDst, bounds);
|
||||
SkASSERT_RELEASE(success);
|
||||
// now don't use bounds, since fDst has the clipped dimensions.
|
||||
|
||||
fTileMatrix = fDevice->ctm();
|
||||
fTileMatrix.postTranslate(SkIntToScalar(-fOrigin.x()), SkIntToScalar(-fOrigin.y()));
|
||||
fDevice->fRCStack.rc().translate(-fOrigin.x(), -fOrigin.y(), &fTileRC);
|
||||
fTileRC.op(SkIRect::MakeWH(fDraw.fDst.width(), fDraw.fDst.height()),
|
||||
SkRegion::kIntersect_Op);
|
||||
|
||||
fCurrOrigin = fOrigin;
|
||||
}
|
||||
|
||||
void stepOrigin() {
|
||||
SkASSERT(!fDone);
|
||||
SkASSERT(fNeedsTiling);
|
||||
fOrigin.fX += kMaxDim;
|
||||
if (fOrigin.fX >= fRootPixmap.width()) { // too far
|
||||
fOrigin.fX = 0;
|
||||
fOrigin.fY += kMaxDim;
|
||||
if (fOrigin.fY >= fRootPixmap.height()) {
|
||||
fDone = true; // way too far
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#define LOOP_TILER(code) \
|
||||
SkDrawTiler priv_tiler(this); \
|
||||
while (const SkDraw* priv_draw = priv_tiler.next()) { \
|
||||
priv_draw->code; \
|
||||
}
|
||||
#define TILER_X(x) (x) - priv_tiler.curr_x()
|
||||
#define TILER_Y(y) (y) - priv_tiler.curr_y()
|
||||
|
||||
|
||||
class SkColorTable;
|
||||
|
||||
static bool valid_for_bitmap_device(const SkImageInfo& info,
|
||||
@ -173,30 +283,17 @@ bool SkBitmapDevice::onReadPixels(const SkPixmap& pm, int x, int y) {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SkBitmapDevice::BDDraw : public SkDraw {
|
||||
public:
|
||||
BDDraw(SkBitmapDevice* dev) {
|
||||
// we need fDst to be set, and if we're actually drawing, to dirty the genID
|
||||
if (!dev->accessPixels(&fDst)) {
|
||||
// NoDrawDevice uses us (why?) so we have to catch this case w/ no pixels
|
||||
fDst.reset(dev->imageInfo(), nullptr, 0);
|
||||
}
|
||||
fMatrix = &dev->ctm();
|
||||
fRC = &dev->fRCStack.rc();
|
||||
}
|
||||
};
|
||||
|
||||
void SkBitmapDevice::drawPaint(const SkPaint& paint) {
|
||||
BDDraw(this).drawPaint(paint);
|
||||
LOOP_TILER( drawPaint(paint))
|
||||
}
|
||||
|
||||
void SkBitmapDevice::drawPoints(SkCanvas::PointMode mode, size_t count,
|
||||
const SkPoint pts[], const SkPaint& paint) {
|
||||
BDDraw(this).drawPoints(mode, count, pts, paint, nullptr);
|
||||
LOOP_TILER( drawPoints(mode, count, pts, paint, nullptr))
|
||||
}
|
||||
|
||||
void SkBitmapDevice::drawRect(const SkRect& r, const SkPaint& paint) {
|
||||
BDDraw(this).drawRect(r, paint);
|
||||
LOOP_TILER( drawRect(r, paint))
|
||||
}
|
||||
|
||||
void SkBitmapDevice::drawOval(const SkRect& oval, const SkPaint& paint) {
|
||||
@ -216,21 +313,27 @@ void SkBitmapDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
|
||||
// required to override drawRRect.
|
||||
this->drawPath(path, paint, nullptr, true);
|
||||
#else
|
||||
BDDraw(this).drawRRect(rrect, paint);
|
||||
LOOP_TILER( drawRRect(rrect, paint))
|
||||
#endif
|
||||
}
|
||||
|
||||
void SkBitmapDevice::drawPath(const SkPath& path,
|
||||
const SkPaint& paint, const SkMatrix* prePathMatrix,
|
||||
bool pathIsMutable) {
|
||||
BDDraw(this).drawPath(path, paint, prePathMatrix, pathIsMutable);
|
||||
SkDrawTiler tiler(this);
|
||||
if (tiler.needsTiling()) {
|
||||
pathIsMutable = false;
|
||||
}
|
||||
while (const SkDraw* draw = tiler.next()) {
|
||||
draw->drawPath(path, paint, prePathMatrix, pathIsMutable);
|
||||
}
|
||||
}
|
||||
|
||||
void SkBitmapDevice::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
|
||||
const SkPaint& paint) {
|
||||
SkMatrix matrix = SkMatrix::MakeTrans(x, y);
|
||||
LogDrawScaleFactor(SkMatrix::Concat(this->ctm(), matrix), paint.getFilterQuality());
|
||||
BDDraw(this).drawBitmap(bitmap, matrix, nullptr, paint);
|
||||
LOOP_TILER( drawBitmap(bitmap, matrix, nullptr, paint))
|
||||
}
|
||||
|
||||
static inline bool CanApplyDstMatrixAsCTM(const SkMatrix& m, const SkPaint& paint) {
|
||||
@ -325,7 +428,7 @@ void SkBitmapDevice::drawBitmapRect(const SkBitmap& bitmap,
|
||||
// matrix with the CTM, and try to call drawSprite if it can. If not,
|
||||
// it will make a shader and call drawRect, as we do below.
|
||||
if (CanApplyDstMatrixAsCTM(matrix, paint)) {
|
||||
BDDraw(this).drawBitmap(*bitmapPtr, matrix, dstPtr, paint);
|
||||
LOOP_TILER( drawBitmap(*bitmapPtr, matrix, dstPtr, paint))
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -354,25 +457,25 @@ void SkBitmapDevice::drawBitmapRect(const SkBitmap& bitmap,
|
||||
}
|
||||
|
||||
void SkBitmapDevice::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& paint) {
|
||||
BDDraw(this).drawSprite(bitmap, x, y, paint);
|
||||
LOOP_TILER( drawSprite(bitmap, TILER_X(x), TILER_Y(y), paint))
|
||||
}
|
||||
|
||||
void SkBitmapDevice::drawText(const void* text, size_t len,
|
||||
SkScalar x, SkScalar y, const SkPaint& paint) {
|
||||
BDDraw(this).drawText((const char*)text, len, x, y, paint, &fSurfaceProps);
|
||||
LOOP_TILER( drawText((const char*)text, len, x, y, paint, &fSurfaceProps))
|
||||
}
|
||||
|
||||
void SkBitmapDevice::drawPosText(const void* text, size_t len, const SkScalar xpos[],
|
||||
int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) {
|
||||
BDDraw(this).drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, paint,
|
||||
&fSurfaceProps);
|
||||
LOOP_TILER( drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, paint,
|
||||
&fSurfaceProps))
|
||||
}
|
||||
|
||||
void SkBitmapDevice::drawVertices(const SkVertices* vertices, SkBlendMode bmode,
|
||||
const SkPaint& paint) {
|
||||
BDDraw(this).drawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(),
|
||||
vertices->texCoords(), vertices->colors(), bmode,
|
||||
vertices->indices(), vertices->indexCount(), paint);
|
||||
LOOP_TILER( drawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(),
|
||||
vertices->texCoords(), vertices->colors(), bmode,
|
||||
vertices->indices(), vertices->indexCount(), paint))
|
||||
}
|
||||
|
||||
void SkBitmapDevice::drawDevice(SkBaseDevice* device, int x, int y, const SkPaint& origPaint) {
|
||||
@ -384,7 +487,8 @@ void SkBitmapDevice::drawDevice(SkBaseDevice* device, int x, int y, const SkPain
|
||||
paint.writable()->setMaskFilter(paint->getMaskFilter()->makeWithLocalMatrix(this->ctm()));
|
||||
}
|
||||
|
||||
BDDraw(this).drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap, x, y, *paint);
|
||||
LOOP_TILER( drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap,
|
||||
TILER_X(x), TILER_Y(y), *paint))
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -144,6 +144,7 @@ private:
|
||||
friend struct DeviceCM; //for setMatrixClip
|
||||
friend class SkDraw;
|
||||
friend class SkDrawIter;
|
||||
friend class SkDrawTiler;
|
||||
friend class SkDeviceFilteredPaint;
|
||||
friend class SkSurface_Raster;
|
||||
friend class SkThreadedBMPDevice; // to copy fRCStack
|
||||
|
@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkDeviceLooper.h"
|
||||
|
||||
SkDeviceLooper::SkDeviceLooper(const SkPixmap& base, const SkRasterClip& rc, const SkIRect& bounds,
|
||||
bool aa)
|
||||
: fBaseDst(base)
|
||||
, fBaseRC(rc)
|
||||
, fDelta(aa ? kAA_Delta : kBW_Delta)
|
||||
{
|
||||
// sentinels that next() has not yet been called, and so our mapper functions
|
||||
// should not be called either.
|
||||
fCurrDst = nullptr;
|
||||
fCurrRC = nullptr;
|
||||
|
||||
if (!rc.isEmpty()) {
|
||||
// clip must be contained by the bitmap
|
||||
SkASSERT(SkIRect::MakeWH(base.width(), base.height()).contains(rc.getBounds()));
|
||||
}
|
||||
|
||||
if (rc.isEmpty() || !fClippedBounds.intersect(bounds, rc.getBounds())) {
|
||||
fState = kDone_State;
|
||||
} else if (this->fitsInDelta(fClippedBounds)) {
|
||||
fState = kSimple_State;
|
||||
} else {
|
||||
// back up by 1 DX, so that next() will put us in a correct starting
|
||||
// position.
|
||||
fCurrOffset.set(fClippedBounds.left() - fDelta,
|
||||
fClippedBounds.top());
|
||||
fState = kComplex_State;
|
||||
}
|
||||
}
|
||||
|
||||
SkDeviceLooper::~SkDeviceLooper() {}
|
||||
|
||||
void SkDeviceLooper::mapRect(SkRect* dst, const SkRect& src) const {
|
||||
SkASSERT(kDone_State != fState);
|
||||
SkASSERT(fCurrDst);
|
||||
SkASSERT(fCurrRC);
|
||||
|
||||
*dst = src;
|
||||
dst->offset(SkIntToScalar(-fCurrOffset.fX),
|
||||
SkIntToScalar(-fCurrOffset.fY));
|
||||
}
|
||||
|
||||
void SkDeviceLooper::mapMatrix(SkMatrix* dst, const SkMatrix& src) const {
|
||||
SkASSERT(kDone_State != fState);
|
||||
SkASSERT(fCurrDst);
|
||||
SkASSERT(fCurrRC);
|
||||
|
||||
*dst = src;
|
||||
dst->postTranslate(SkIntToScalar(-fCurrOffset.fX), SkIntToScalar(-fCurrOffset.fY));
|
||||
}
|
||||
|
||||
bool SkDeviceLooper::computeCurrBitmapAndClip() {
|
||||
SkASSERT(kComplex_State == fState);
|
||||
|
||||
SkIRect r = SkIRect::MakeXYWH(fCurrOffset.x(), fCurrOffset.y(),
|
||||
fDelta, fDelta);
|
||||
if (!fBaseDst.extractSubset(&fSubsetDst, r)) {
|
||||
fSubsetRC.setEmpty();
|
||||
} else {
|
||||
fBaseRC.translate(-r.left(), -r.top(), &fSubsetRC);
|
||||
(void)fSubsetRC.op(SkIRect::MakeWH(fDelta, fDelta), SkRegion::kIntersect_Op);
|
||||
}
|
||||
|
||||
fCurrDst = &fSubsetDst;
|
||||
fCurrRC = &fSubsetRC;
|
||||
return !fCurrRC->isEmpty();
|
||||
}
|
||||
|
||||
static bool next_tile(const SkIRect& boundary, int delta, SkIPoint* offset) {
|
||||
// can we move to the right?
|
||||
if (offset->x() + delta < boundary.right()) {
|
||||
offset->fX += delta;
|
||||
return true;
|
||||
}
|
||||
|
||||
// reset to the left, but move down a row
|
||||
offset->fX = boundary.left();
|
||||
if (offset->y() + delta < boundary.bottom()) {
|
||||
offset->fY += delta;
|
||||
return true;
|
||||
}
|
||||
|
||||
// offset is now outside of boundary, so we're done
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkDeviceLooper::next() {
|
||||
switch (fState) {
|
||||
case kDone_State:
|
||||
// in theory, we should not get called here, since we must have
|
||||
// previously returned false, but we check anyway.
|
||||
break;
|
||||
|
||||
case kSimple_State:
|
||||
// first time for simple
|
||||
if (nullptr == fCurrDst) {
|
||||
fCurrDst = &fBaseDst;
|
||||
fCurrRC = &fBaseRC;
|
||||
fCurrOffset.set(0, 0);
|
||||
return true;
|
||||
}
|
||||
// 2nd time for simple, we are done
|
||||
break;
|
||||
|
||||
case kComplex_State:
|
||||
// need to propogate fCurrOffset through clippedbounds
|
||||
// left to right, until we wrap around and move down
|
||||
|
||||
while (next_tile(fClippedBounds, fDelta, &fCurrOffset)) {
|
||||
if (this->computeCurrBitmapAndClip()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
fState = kDone_State;
|
||||
return false;
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkDeviceLooper_DEFINED
|
||||
#define SkDeviceLooper_DEFINED
|
||||
|
||||
#include "SkBitmap.h"
|
||||
#include "SkMatrix.h"
|
||||
#include "SkRasterClip.h"
|
||||
|
||||
/**
|
||||
* Helper class to manage "tiling" a large coordinate space into managable
|
||||
* chunks, where managable means areas that are <= some max critical coordinate
|
||||
* size.
|
||||
*
|
||||
* The constructor takes an antialiasing bool, which affects what this maximum
|
||||
* allowable size is: If we're drawing BW, then we need coordinates to stay
|
||||
* safely within fixed-point range (we use +- 16K, to give ourselves room to
|
||||
* add/subtract two fixed values and still be in range. If we're drawing AA,
|
||||
* then we reduce that size by the amount that the supersampler scan converter
|
||||
* needs (at the moment, that is 4X, so the "safe" range is +- 4K).
|
||||
*
|
||||
* For performance reasons, the class first checks to see if any help is needed
|
||||
* at all, and if not (i.e. the specified bounds and base bitmap area already
|
||||
* in the safe-zone, then the class does nothing (effectively).
|
||||
*/
|
||||
class SkDeviceLooper {
|
||||
public:
|
||||
SkDeviceLooper(const SkPixmap& base, const SkRasterClip&, const SkIRect& bounds, bool aa);
|
||||
~SkDeviceLooper();
|
||||
|
||||
const SkPixmap& getPixmap() const {
|
||||
SkASSERT(kDone_State != fState);
|
||||
SkASSERT(fCurrDst);
|
||||
return *fCurrDst;
|
||||
}
|
||||
|
||||
const SkRasterClip& getRC() const {
|
||||
SkASSERT(kDone_State != fState);
|
||||
SkASSERT(fCurrRC);
|
||||
return *fCurrRC;
|
||||
}
|
||||
|
||||
void mapRect(SkRect* dst, const SkRect& src) const;
|
||||
void mapMatrix(SkMatrix* dst, const SkMatrix& src) const;
|
||||
|
||||
/**
|
||||
* Call next to setup the looper to return a valid coordinate chunk.
|
||||
* Each time this returns true, it is safe to call mapRect() and
|
||||
* mapMatrix(), to convert from "global" coordinate values to ones that
|
||||
* are local to this chunk.
|
||||
*
|
||||
* When next() returns false, the list of chunks is done, and mapRect()
|
||||
* and mapMatrix() should no longer be called.
|
||||
*/
|
||||
bool next();
|
||||
|
||||
private:
|
||||
const SkPixmap& fBaseDst;
|
||||
const SkRasterClip& fBaseRC;
|
||||
|
||||
enum State {
|
||||
kDone_State, // iteration is complete, getters will assert
|
||||
kSimple_State, // no translate/clip mods needed
|
||||
kComplex_State
|
||||
};
|
||||
|
||||
// storage for our tiled versions. Perhaps could use SkTLazy
|
||||
SkPixmap fSubsetDst;
|
||||
SkRasterClip fSubsetRC;
|
||||
|
||||
const SkPixmap* fCurrDst;
|
||||
const SkRasterClip* fCurrRC;
|
||||
SkIRect fClippedBounds;
|
||||
SkIPoint fCurrOffset;
|
||||
int fDelta;
|
||||
State fState;
|
||||
|
||||
enum Delta {
|
||||
kBW_Delta = 1 << 14, // 16K, gives room to spare for fixedpoint
|
||||
kAA_Delta = kBW_Delta >> 2 // supersample 4x
|
||||
};
|
||||
|
||||
bool fitsInDelta(const SkIRect& r) const {
|
||||
return r.right() < fDelta && r.bottom() < fDelta;
|
||||
}
|
||||
|
||||
bool computeCurrBitmapAndClip();
|
||||
};
|
||||
|
||||
#endif
|
@ -14,7 +14,6 @@
|
||||
#include "SkCanvas.h"
|
||||
#include "SkColorData.h"
|
||||
#include "SkDevice.h"
|
||||
#include "SkDeviceLooper.h"
|
||||
#include "SkDraw.h"
|
||||
#include "SkDrawProcs.h"
|
||||
#include "SkFindAndPlaceGlyph.h"
|
||||
@ -785,8 +784,7 @@ void SkDraw::drawRect(const SkRect& prePaintRect, const SkPaint& paint,
|
||||
}
|
||||
}
|
||||
|
||||
if (!SkRectPriv::MakeLargeS32().contains(bbox)) {
|
||||
// bbox.roundOut() is undefined; use slow path.
|
||||
if (!SkRectPriv::FitsInFixed(bbox) && rtype != kHair_RectType) {
|
||||
draw_rect_as_path(*this, prePaintRect, paint, matrix);
|
||||
return;
|
||||
}
|
||||
@ -796,45 +794,37 @@ void SkDraw::drawRect(const SkRect& prePaintRect, const SkPaint& paint,
|
||||
return;
|
||||
}
|
||||
|
||||
SkDeviceLooper looper(fDst, *fRC, ir, paint.isAntiAlias());
|
||||
while (looper.next()) {
|
||||
SkRect localDevRect;
|
||||
looper.mapRect(&localDevRect, devRect);
|
||||
SkMatrix localMatrix;
|
||||
looper.mapMatrix(&localMatrix, *matrix);
|
||||
SkAutoBlitterChoose blitterStorage(fDst, *matrix, paint);
|
||||
const SkRasterClip& clip = *fRC;
|
||||
SkBlitter* blitter = blitterStorage.get();
|
||||
|
||||
SkAutoBlitterChoose blitterStorage(looper.getPixmap(), localMatrix, paint);
|
||||
const SkRasterClip& clip = looper.getRC();
|
||||
SkBlitter* blitter = blitterStorage.get();
|
||||
|
||||
// we want to "fill" if we are kFill or kStrokeAndFill, since in the latter
|
||||
// case we are also hairline (if we've gotten to here), which devolves to
|
||||
// effectively just kFill
|
||||
switch (rtype) {
|
||||
case kFill_RectType:
|
||||
if (paint.isAntiAlias()) {
|
||||
SkScan::AntiFillRect(localDevRect, clip, blitter);
|
||||
} else {
|
||||
SkScan::FillRect(localDevRect, clip, blitter);
|
||||
}
|
||||
break;
|
||||
case kStroke_RectType:
|
||||
if (paint.isAntiAlias()) {
|
||||
SkScan::AntiFrameRect(localDevRect, strokeSize, clip, blitter);
|
||||
} else {
|
||||
SkScan::FrameRect(localDevRect, strokeSize, clip, blitter);
|
||||
}
|
||||
break;
|
||||
case kHair_RectType:
|
||||
if (paint.isAntiAlias()) {
|
||||
SkScan::AntiHairRect(localDevRect, clip, blitter);
|
||||
} else {
|
||||
SkScan::HairRect(localDevRect, clip, blitter);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SkDEBUGFAIL("bad rtype");
|
||||
}
|
||||
// we want to "fill" if we are kFill or kStrokeAndFill, since in the latter
|
||||
// case we are also hairline (if we've gotten to here), which devolves to
|
||||
// effectively just kFill
|
||||
switch (rtype) {
|
||||
case kFill_RectType:
|
||||
if (paint.isAntiAlias()) {
|
||||
SkScan::AntiFillRect(devRect, clip, blitter);
|
||||
} else {
|
||||
SkScan::FillRect(devRect, clip, blitter);
|
||||
}
|
||||
break;
|
||||
case kStroke_RectType:
|
||||
if (paint.isAntiAlias()) {
|
||||
SkScan::AntiFrameRect(devRect, strokeSize, clip, blitter);
|
||||
} else {
|
||||
SkScan::FrameRect(devRect, strokeSize, clip, blitter);
|
||||
}
|
||||
break;
|
||||
case kHair_RectType:
|
||||
if (paint.isAntiAlias()) {
|
||||
SkScan::AntiHairRect(devRect, clip, blitter);
|
||||
} else {
|
||||
SkScan::HairRect(devRect, clip, blitter);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SkDEBUGFAIL("bad rtype");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,14 +144,25 @@ void SkScan::HairLineRgn(const SkPoint array[], int arrayCount, const SkRegion*
|
||||
|
||||
// we don't just draw 4 lines, 'cause that can leave a gap in the bottom-right
|
||||
// and double-hit the top-left.
|
||||
void SkScan::HairRect(const SkRect& rect, const SkRasterClip& clip,
|
||||
SkBlitter* blitter) {
|
||||
void SkScan::HairRect(const SkRect& rect, const SkRasterClip& clip, SkBlitter* blitter) {
|
||||
SkAAClipBlitterWrapper wrapper;
|
||||
SkBlitterClipper clipper;
|
||||
const SkIRect r = SkIRect::MakeLTRB(SkScalarFloorToInt(rect.fLeft),
|
||||
SkScalarFloorToInt(rect.fTop),
|
||||
SkScalarFloorToInt(rect.fRight) + 1,
|
||||
SkScalarFloorToInt(rect.fBottom) + 1);
|
||||
// Create the enclosing bounds of the hairrect. i.e. we will stroke the interior of r.
|
||||
SkIRect r = SkIRect::MakeLTRB(SkScalarFloorToInt(rect.fLeft),
|
||||
SkScalarFloorToInt(rect.fTop),
|
||||
SkScalarFloorToInt(rect.fRight + 1),
|
||||
SkScalarFloorToInt(rect.fBottom + 1));
|
||||
|
||||
// Note: r might be crazy big, if rect was huge, possibly getting pinned to max/min s32.
|
||||
// We need to trim it back to something reasonable before we can query its width etc.
|
||||
// since r.fRight - r.fLeft might wrap around to negative even if fRight > fLeft.
|
||||
//
|
||||
// We outset the clip bounds by 1 before intersecting, since r is being stroked and not filled
|
||||
// so we don't want to pin an edge of it to the clip. The intersect's job is mostly to just
|
||||
// get the actual edge values into a reasonable range (e.g. so width() can't overflow).
|
||||
if (!r.intersect(clip.getBounds().makeOutset(1, 1))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clip.quickReject(r)) {
|
||||
return;
|
||||
|
@ -933,6 +933,13 @@ void AAHairlineOp::onPrepareDraws(Target* target) {
|
||||
|
||||
int lineCount = lines.count() / 2;
|
||||
int conicCount = conics.count() / 3;
|
||||
int quadAndConicCount = conicCount + quadCount;
|
||||
|
||||
static constexpr int kMaxLines = SK_MaxS32 / kLineSegNumVertices;
|
||||
static constexpr int kMaxQuadsAndConics = SK_MaxS32 / kQuadNumVertices;
|
||||
if (lineCount > kMaxLines || quadAndConicCount > kMaxQuadsAndConics) {
|
||||
return;
|
||||
}
|
||||
|
||||
const GrPipeline* pipeline = fHelper.makePipeline(target);
|
||||
// do lines first
|
||||
@ -1000,7 +1007,7 @@ void AAHairlineOp::onPrepareDraws(Target* target) {
|
||||
sk_sp<const GrBuffer> quadsIndexBuffer = get_quads_index_buffer(target->resourceProvider());
|
||||
|
||||
size_t vertexStride = sizeof(BezierVertex);
|
||||
int vertexCount = kQuadNumVertices * quadCount + kQuadNumVertices * conicCount;
|
||||
int vertexCount = kQuadNumVertices * quadAndConicCount;
|
||||
void *vertices = target->makeVertexSpace(vertexStride, vertexCount,
|
||||
&vertexBuffer, &firstVertex);
|
||||
|
||||
|
@ -209,8 +209,7 @@ public:
|
||||
fEntries[0].fClipStack = existingClipStack;
|
||||
}
|
||||
|
||||
void updateClip(const SkClipStack& clipStack,
|
||||
const SkPoint& translation, const SkRect& bounds);
|
||||
void updateClip(const SkClipStack& clipStack, const SkIRect& bounds);
|
||||
void updateMatrix(const SkMatrix& matrix);
|
||||
void updateDrawingState(const SkPDFDevice::GraphicStateEntry& state);
|
||||
|
||||
@ -283,56 +282,11 @@ bool apply_clip(SkClipOp op, const SkPath& u, const SkPath& v, SkPath* r) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Uses Path Ops to calculate a vector SkPath clip from a clip stack.
|
||||
* Returns true if successful, or false if not successful.
|
||||
* If successful, the resulting clip is stored in outClipPath.
|
||||
* If not successful, outClipPath is undefined, and a fallback method
|
||||
* should be used.
|
||||
*/
|
||||
static bool get_clip_stack_path(const SkMatrix& transform,
|
||||
const SkClipStack& clipStack,
|
||||
const SkRect& bounds,
|
||||
SkPath* outClipPath) {
|
||||
outClipPath->reset();
|
||||
outClipPath->setFillType(SkPath::kInverseWinding_FillType);
|
||||
|
||||
const SkClipStack::Element* clipEntry;
|
||||
SkClipStack::Iter iter;
|
||||
iter.reset(clipStack, SkClipStack::Iter::kBottom_IterStart);
|
||||
for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) {
|
||||
SkPath entryPath;
|
||||
if (SkClipStack::Element::DeviceSpaceType::kEmpty == clipEntry->getDeviceSpaceType()) {
|
||||
outClipPath->reset();
|
||||
outClipPath->setFillType(SkPath::kInverseWinding_FillType);
|
||||
continue;
|
||||
} else {
|
||||
clipEntry->asDeviceSpacePath(&entryPath);
|
||||
}
|
||||
entryPath.transform(transform);
|
||||
if (!apply_clip(clipEntry->getOp(), *outClipPath, entryPath, outClipPath)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (outClipPath->isInverseFillType()) {
|
||||
// The bounds are slightly outset to ensure this is correct in the
|
||||
// face of floating-point accuracy and possible SkRegion bitmap
|
||||
// approximations.
|
||||
SkRect clipBounds = bounds;
|
||||
clipBounds.outset(SK_Scalar1, SK_Scalar1);
|
||||
if (!calculate_inverse_path(clipBounds, *outClipPath, outClipPath)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO(vandebo): Take advantage of SkClipStack::getSaveCount(), the PDF
|
||||
// graphic state stack, and the fact that we can know all the clips used
|
||||
// on the page to optimize this.
|
||||
void GraphicStackState::updateClip(const SkClipStack& clipStack,
|
||||
const SkPoint& translation,
|
||||
const SkRect& bounds) {
|
||||
const SkIRect& bounds) {
|
||||
if (clipStack == currentEntry()->fClipStack) {
|
||||
return;
|
||||
}
|
||||
@ -347,11 +301,16 @@ void GraphicStackState::updateClip(const SkClipStack& clipStack,
|
||||
|
||||
currentEntry()->fClipStack = clipStack;
|
||||
|
||||
SkMatrix transform;
|
||||
transform.setTranslate(translation.fX, translation.fY);
|
||||
|
||||
SkPath clipPath;
|
||||
if (get_clip_stack_path(transform, clipStack, bounds, &clipPath)) {
|
||||
(void)clipStack.asPath(&clipPath);
|
||||
|
||||
// The bounds are slightly outset to ensure this is correct in the
|
||||
// face of floating-point accuracy and possible SkRegion bitmap
|
||||
// approximations.
|
||||
SkPath clipBoundsPath;
|
||||
clipBoundsPath.addRect(SkRect::Make(bounds.makeOutset(1, 1)));
|
||||
|
||||
if (Op(clipPath, clipBoundsPath, kIntersect_SkPathOp, &clipPath)) {
|
||||
SkPDFUtils::EmitPath(clipPath, SkPaint::kFill_Style, fContentStream);
|
||||
SkPath::FillType clipFill = clipPath.getFillType();
|
||||
NOT_IMPLEMENTED(clipFill == SkPath::kInverseEvenOdd_FillType, false);
|
||||
@ -1776,8 +1735,7 @@ std::unique_ptr<SkStreamAsset> SkPDFDevice::content() const {
|
||||
|
||||
GraphicStackState gsState(fExistingClipStack, &buffer);
|
||||
for (const auto& entry : fContentEntries) {
|
||||
gsState.updateClip(entry.fState.fClipStack,
|
||||
{0, 0}, SkRect::Make(this->bounds()));
|
||||
gsState.updateClip(entry.fState.fClipStack, this->bounds());
|
||||
gsState.updateMatrix(entry.fState.fMatrix);
|
||||
gsState.updateDrawingState(entry.fState);
|
||||
|
||||
|
@ -120,6 +120,10 @@ void SkPDFUtils::AppendRectangle(const SkRect& rect, SkWStream* content) {
|
||||
void SkPDFUtils::EmitPath(const SkPath& path, SkPaint::Style paintStyle,
|
||||
bool doConsumeDegerates, SkWStream* content,
|
||||
SkScalar tolerance) {
|
||||
if (path.isEmpty() && SkPaint::kFill_Style == paintStyle) {
|
||||
SkPDFUtils::AppendRectangle({0, 0, 0, 0}, content);
|
||||
return;
|
||||
}
|
||||
// Filling a path with no area results in a drawing in PDF renderers but
|
||||
// Chrome expects to be able to draw some such entities with no visible
|
||||
// result, so we detect those cases and discard the drawing for them.
|
||||
|
@ -92,7 +92,9 @@ public:
|
||||
bool isNativelyFocal() const { return this->isFocal() && fData.fFocalData.isNativelyFocal(); }
|
||||
|
||||
// Note that focalX = f = r0 / (r0 - r1), so 1 - focalX > 0 == r0 < r1
|
||||
bool isRadiusIncreasing() const { return this->isFocal() && 1 - fData.fFocalData.fFocalX > 0; }
|
||||
bool isRadiusIncreasing() const {
|
||||
return this->isFocal() ? 1 - fData.fFocalData.fFocalX > 0 : this->diffRadius() > 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
void onGetGLSLProcessorKey(const GrShaderCaps& c, GrProcessorKeyBuilder* b) const override {
|
||||
@ -237,7 +239,8 @@ protected:
|
||||
const char* p = coords2D.c_str();
|
||||
|
||||
if (effect.getType() == Type::kRadial) {
|
||||
fragBuilder->codeAppendf("half %s = length(%s) - %s;", tName, p, p0.c_str());
|
||||
char sign = effect.diffRadius() < 0 ? '-' : '+';
|
||||
fragBuilder->codeAppendf("half %s = %clength(%s) - %s;", tName, sign, p, p0.c_str());
|
||||
} else {
|
||||
// output will default to transparent black (we simply won't write anything
|
||||
// else to it if invalid, instead of discarding or returning prematurely)
|
||||
@ -263,8 +266,9 @@ protected:
|
||||
void onSetData(const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& p) override {
|
||||
INHERITED::onSetData(pdman, p);
|
||||
const TwoPointConicalEffect& effect = p.cast<TwoPointConicalEffect>();
|
||||
// kRadialType should imply r1 - r0 = 1 (after our transformation) so r0 = r0 / (r1 - r0)
|
||||
SkASSERT(effect.getType() == Type::kStrip || SkScalarNearlyZero(effect.diffRadius() - 1));
|
||||
// kRadialType should imply |r1 - r0| = 1 (after our transformation)
|
||||
SkASSERT(effect.getType() == Type::kStrip ||
|
||||
SkScalarNearlyZero(SkTAbs(effect.diffRadius()) - 1));
|
||||
pdman.set1f(fParamUni, effect.getType() == Type::kRadial ? effect.r0()
|
||||
: effect.r0() * effect.r0());
|
||||
}
|
||||
@ -407,12 +411,14 @@ std::unique_ptr<GrFragmentProcessor> Gr2PtConicalGradientEffect::Make(
|
||||
TwoPointConicalEffect::Data::Data(const SkTwoPointConicalGradient& shader, SkMatrix& matrix) {
|
||||
fType = shader.getType();
|
||||
if (fType == Type::kRadial) {
|
||||
SkScalar dr = shader.getDiffRadius();
|
||||
// Map center to (0, 0) and scale dr to 1
|
||||
// Map center to (0, 0)
|
||||
matrix.postTranslate(-shader.getStartCenter().fX, -shader.getStartCenter().fY);
|
||||
|
||||
// scale |fDiffRadius| to 1
|
||||
SkScalar dr = shader.getDiffRadius();
|
||||
matrix.postScale(1 / dr, 1 / dr);
|
||||
fRadius0 = shader.getStartRadius() / dr;
|
||||
fDiffRadius = 1;
|
||||
fDiffRadius = dr < 0 ? -1 : 1;
|
||||
} else if (fType == Type::kStrip) {
|
||||
fRadius0 = shader.getStartRadius() / shader.getCenterX1();
|
||||
fDiffRadius = 0;
|
||||
|
@ -35,7 +35,7 @@ fuzzy(180,3) == grid-abspos-items-002.html grid-abspos-items-002-ref.html # flat
|
||||
fuzzy-if(skiaContent,1,200) == grid-order-placement-definite-001.html grid-order-placement-definite-001-ref.html
|
||||
skip-if(Android) == grid-placement-definite-implicit-001.html grid-placement-definite-implicit-001-ref.html
|
||||
== grid-placement-definite-implicit-002.html grid-placement-definite-implicit-002-ref.html
|
||||
skip-if(Android) fuzzy-if(winWidget,1,32) == grid-placement-auto-implicit-001.html grid-placement-auto-implicit-001-ref.html
|
||||
fuzzy-if(skiaContent,64,1) skip-if(Android) == grid-placement-auto-implicit-001.html grid-placement-auto-implicit-001-ref.html
|
||||
== grid-placement-abspos-implicit-001.html grid-placement-abspos-implicit-001-ref.html
|
||||
== rtl-grid-placement-definite-001.html rtl-grid-placement-definite-001-ref.html
|
||||
== rtl-grid-placement-auto-row-sparse-001.html rtl-grid-placement-auto-row-sparse-001-ref.html
|
||||
|
Loading…
x
Reference in New Issue
Block a user