mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Bug 1221840. Support repeating images in 1 axis. r=seth
This commit is contained in:
parent
c89963ec79
commit
e74c79f0e3
@ -714,7 +714,7 @@ DrawGradient(CGColorSpaceRef aColorSpace,
|
||||
|
||||
CGContextDrawLinearGradient(cg, stops->mGradient, startPoint, endPoint,
|
||||
kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
|
||||
} else if (stops->mExtend == ExtendMode::REPEAT || stops->mExtend == ExtendMode::REFLECT) {
|
||||
} else {
|
||||
DrawLinearRepeatingGradient(aColorSpace, cg, pat, extents, stops->mExtend == ExtendMode::REFLECT);
|
||||
}
|
||||
} else if (aPattern.GetType() == PatternType::RADIAL_GRADIENT) {
|
||||
@ -734,7 +734,7 @@ DrawGradient(CGColorSpaceRef aColorSpace,
|
||||
//XXX: are there degenerate radial gradients that we should avoid drawing?
|
||||
CGContextDrawRadialGradient(cg, stops->mGradient, startCenter, startRadius, endCenter, endRadius,
|
||||
kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
|
||||
} else if (stops->mExtend == ExtendMode::REPEAT || stops->mExtend == ExtendMode::REFLECT) {
|
||||
} else {
|
||||
DrawRadialRepeatingGradient(aColorSpace, cg, pat, extents, stops->mExtend == ExtendMode::REFLECT);
|
||||
}
|
||||
} else {
|
||||
@ -775,8 +775,14 @@ isGradient(const Pattern &aPattern)
|
||||
static bool
|
||||
isNonRepeatingSurface(const Pattern& aPattern)
|
||||
{
|
||||
return aPattern.GetType() == PatternType::SURFACE &&
|
||||
static_cast<const SurfacePattern&>(aPattern).mExtendMode != ExtendMode::REPEAT;
|
||||
if (aPattern.GetType() != PatternType::SURFACE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const SurfacePattern& surfacePattern = static_cast<const SurfacePattern&>(aPattern);
|
||||
return surfacePattern.mExtendMode != ExtendMode::REPEAT &&
|
||||
surfacePattern.mExtendMode != ExtendMode::REPEAT_X &&
|
||||
surfacePattern.mExtendMode != ExtendMode::REPEAT_Y;
|
||||
}
|
||||
|
||||
/* CoreGraphics patterns ignore the userspace transform so
|
||||
@ -815,6 +821,15 @@ CreateCGPattern(const Pattern &aPattern, CGAffineTransform aUserSpace)
|
||||
// wkPatternTilingConstantSpacing
|
||||
// } wkPatternTiling;
|
||||
// extern CGPatternRef (*wkCGPatternCreateWithImageAndTransform)(CGImageRef, CGAffineTransform, int);
|
||||
break;
|
||||
case ExtendMode::REPEAT_X:
|
||||
xStep = static_cast<CGFloat>(CGImageGetWidth(image));
|
||||
yStep = static_cast<CGFloat>(1 << 22);
|
||||
break;
|
||||
case ExtendMode::REPEAT_Y:
|
||||
yStep = static_cast<CGFloat>(CGImageGetHeight(image));
|
||||
xStep = static_cast<CGFloat>(1 << 22);
|
||||
break;
|
||||
}
|
||||
|
||||
//XXX: We should be using CGContextDrawTiledImage when we can. Even though it
|
||||
|
@ -1318,7 +1318,7 @@ DrawTargetD2D::CreateGradientStops(GradientStop *rawStops, uint32_t aNumStops, E
|
||||
|
||||
HRESULT hr =
|
||||
mRT->CreateGradientStopCollection(stops, aNumStops,
|
||||
D2D1_GAMMA_2_2, D2DExtend(aExtendMode),
|
||||
D2D1_GAMMA_2_2, D2DExtend(aExtendMode, Axis::BOTH),
|
||||
getter_AddRefs(stopCollection));
|
||||
delete [] stops;
|
||||
|
||||
@ -2445,9 +2445,11 @@ DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
|
||||
break;
|
||||
}
|
||||
|
||||
D2D1_EXTEND_MODE xRepeat = D2DExtend(pat->mExtendMode, Axis::X_AXIS);
|
||||
D2D1_EXTEND_MODE yRepeat = D2DExtend(pat->mExtendMode, Axis::Y_AXIS);
|
||||
HRESULT hr = mRT->CreateBitmapBrush(bitmap,
|
||||
D2D1::BitmapBrushProperties(D2DExtend(pat->mExtendMode),
|
||||
D2DExtend(pat->mExtendMode),
|
||||
D2D1::BitmapBrushProperties(xRepeat,
|
||||
yRepeat,
|
||||
D2DFilter(pat->mFilter)),
|
||||
D2D1::BrushProperties(aAlpha, D2DMatrix(mat)),
|
||||
getter_AddRefs(bmBrush));
|
||||
|
@ -805,7 +805,7 @@ DrawTargetD2D1::CreateGradientStops(GradientStop *rawStops, uint32_t aNumStops,
|
||||
|
||||
HRESULT hr =
|
||||
mDC->CreateGradientStopCollection(stops, aNumStops,
|
||||
D2D1_GAMMA_2_2, D2DExtend(aExtendMode),
|
||||
D2D1_GAMMA_2_2, D2DExtend(aExtendMode, Axis::BOTH),
|
||||
getter_AddRefs(stopCollection));
|
||||
delete [] stops;
|
||||
|
||||
@ -1468,10 +1468,15 @@ DrawTargetD2D1::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
|
||||
RefPtr<ID2D1Bitmap> bitmap;
|
||||
image->QueryInterface((ID2D1Bitmap**)getter_AddRefs(bitmap));
|
||||
if (bitmap) {
|
||||
/**
|
||||
* Create the brush with the proper repeat modes.
|
||||
*/
|
||||
RefPtr<ID2D1BitmapBrush> bitmapBrush;
|
||||
D2D1_EXTEND_MODE xRepeat = D2DExtend(pat->mExtendMode, Axis::X_AXIS);
|
||||
D2D1_EXTEND_MODE yRepeat = D2DExtend(pat->mExtendMode, Axis::Y_AXIS);
|
||||
|
||||
mDC->CreateBitmapBrush(bitmap,
|
||||
D2D1::BitmapBrushProperties(D2DExtend(pat->mExtendMode),
|
||||
D2DExtend(pat->mExtendMode),
|
||||
D2D1::BitmapBrushProperties(xRepeat, yRepeat,
|
||||
D2DFilter(pat->mFilter)),
|
||||
D2D1::BrushProperties(aAlpha, D2DMatrix(mat)),
|
||||
getter_AddRefs(bitmapBrush));
|
||||
@ -1495,10 +1500,14 @@ DrawTargetD2D1::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
|
||||
// We will do a partial upload of the sampling restricted area from GetImageForSurface.
|
||||
samplingBounds = D2D1::RectF(0, 0, pat->mSamplingRect.width, pat->mSamplingRect.height);
|
||||
}
|
||||
|
||||
D2D1_EXTEND_MODE xRepeat = D2DExtend(pat->mExtendMode, Axis::X_AXIS);
|
||||
D2D1_EXTEND_MODE yRepeat = D2DExtend(pat->mExtendMode, Axis::Y_AXIS);
|
||||
|
||||
mDC->CreateImageBrush(image,
|
||||
D2D1::ImageBrushProperties(samplingBounds,
|
||||
D2DExtend(pat->mExtendMode),
|
||||
D2DExtend(pat->mExtendMode),
|
||||
xRepeat,
|
||||
yRepeat,
|
||||
D2DInterpolationMode(pat->mFilter)),
|
||||
D2D1::BrushProperties(aAlpha, D2DMatrix(mat)),
|
||||
getter_AddRefs(imageBrush));
|
||||
|
@ -186,7 +186,7 @@ SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, TempBitmap& aTmpBitmap
|
||||
case PatternType::LINEAR_GRADIENT: {
|
||||
const LinearGradientPattern& pat = static_cast<const LinearGradientPattern&>(aPattern);
|
||||
GradientStopsSkia *stops = static_cast<GradientStopsSkia*>(pat.mStops.get());
|
||||
SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode);
|
||||
SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode, Axis::BOTH);
|
||||
|
||||
if (stops->mCount >= 2) {
|
||||
SkPoint points[2];
|
||||
@ -215,7 +215,7 @@ SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, TempBitmap& aTmpBitmap
|
||||
case PatternType::RADIAL_GRADIENT: {
|
||||
const RadialGradientPattern& pat = static_cast<const RadialGradientPattern&>(aPattern);
|
||||
GradientStopsSkia *stops = static_cast<GradientStopsSkia*>(pat.mStops.get());
|
||||
SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode);
|
||||
SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode, Axis::BOTH);
|
||||
|
||||
if (stops->mCount >= 2) {
|
||||
SkPoint points[2];
|
||||
@ -257,8 +257,10 @@ SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, TempBitmap& aTmpBitmap
|
||||
mat.preTranslate(rect.x(), rect.y());
|
||||
}
|
||||
|
||||
SkShader::TileMode mode = ExtendModeToTileMode(pat.mExtendMode);
|
||||
SkShader* shader = SkShader::CreateBitmapShader(bitmap, mode, mode);
|
||||
SkShader::TileMode xTileMode = ExtendModeToTileMode(pat.mExtendMode, Axis::X_AXIS);
|
||||
SkShader::TileMode yTileMode = ExtendModeToTileMode(pat.mExtendMode, Axis::Y_AXIS);
|
||||
|
||||
SkShader* shader = SkShader::CreateBitmapShader(bitmap, xTileMode, yTileMode);
|
||||
SkShader* matrixShader = SkShader::CreateLocalMatrixShader(shader, mat);
|
||||
SkSafeUnref(shader);
|
||||
SkSafeUnref(aPaint.setShader(matrixShader));
|
||||
|
@ -133,6 +133,10 @@ GfxExtendToCairoExtend(ExtendMode extend)
|
||||
{
|
||||
case ExtendMode::CLAMP:
|
||||
return CAIRO_EXTEND_PAD;
|
||||
// Cairo doesn't support tiling in only 1 direction,
|
||||
// So we have to fallback and tile in both.
|
||||
case ExtendMode::REPEAT_X:
|
||||
case ExtendMode::REPEAT_Y:
|
||||
case ExtendMode::REPEAT:
|
||||
return CAIRO_EXTEND_REPEAT;
|
||||
case ExtendMode::REFLECT:
|
||||
|
@ -45,13 +45,27 @@ static inline D2D1_RECT_F D2DRect(const T &aRect)
|
||||
return D2D1::RectF(aRect.x, aRect.y, aRect.XMost(), aRect.YMost());
|
||||
}
|
||||
|
||||
static inline D2D1_EXTEND_MODE D2DExtend(ExtendMode aExtendMode)
|
||||
static inline D2D1_EXTEND_MODE D2DExtend(ExtendMode aExtendMode, Axis aAxis)
|
||||
{
|
||||
D2D1_EXTEND_MODE extend;
|
||||
switch (aExtendMode) {
|
||||
case ExtendMode::REPEAT:
|
||||
extend = D2D1_EXTEND_MODE_WRAP;
|
||||
break;
|
||||
case ExtendMode::REPEAT_X:
|
||||
{
|
||||
extend = aAxis == Axis::X_AXIS
|
||||
? D2D1_EXTEND_MODE_WRAP
|
||||
: D2D1_EXTEND_MODE_CLAMP;
|
||||
break;
|
||||
}
|
||||
case ExtendMode::REPEAT_Y:
|
||||
{
|
||||
extend = aAxis == Axis::Y_AXIS
|
||||
? D2D1_EXTEND_MODE_WRAP
|
||||
: D2D1_EXTEND_MODE_CLAMP;
|
||||
break;
|
||||
}
|
||||
case ExtendMode::REFLECT:
|
||||
extend = D2D1_EXTEND_MODE_MIRROR;
|
||||
break;
|
||||
|
@ -291,7 +291,7 @@ SkRectToRect(const SkRect &aRect)
|
||||
}
|
||||
|
||||
static inline SkShader::TileMode
|
||||
ExtendModeToTileMode(ExtendMode aMode)
|
||||
ExtendModeToTileMode(ExtendMode aMode, Axis aAxis)
|
||||
{
|
||||
switch (aMode)
|
||||
{
|
||||
@ -301,6 +301,18 @@ ExtendModeToTileMode(ExtendMode aMode)
|
||||
return SkShader::kRepeat_TileMode;
|
||||
case ExtendMode::REFLECT:
|
||||
return SkShader::kMirror_TileMode;
|
||||
case ExtendMode::REPEAT_X:
|
||||
{
|
||||
return aAxis == Axis::X_AXIS
|
||||
? SkShader::kRepeat_TileMode
|
||||
: SkShader::kClamp_TileMode;
|
||||
}
|
||||
case ExtendMode::REPEAT_Y:
|
||||
{
|
||||
return aAxis == Axis::Y_AXIS
|
||||
? SkShader::kRepeat_TileMode
|
||||
: SkShader::kClamp_TileMode;
|
||||
}
|
||||
}
|
||||
return SkShader::kClamp_TileMode;
|
||||
}
|
||||
|
@ -202,10 +202,18 @@ enum class CompositionOp : int8_t {
|
||||
OP_COUNT
|
||||
};
|
||||
|
||||
enum class Axis : int8_t {
|
||||
X_AXIS,
|
||||
Y_AXIS,
|
||||
BOTH
|
||||
};
|
||||
|
||||
enum class ExtendMode : int8_t {
|
||||
CLAMP,
|
||||
REPEAT,
|
||||
REFLECT
|
||||
CLAMP, // Do not repeat
|
||||
REPEAT, // Repeat in both axis
|
||||
REPEAT_X, // Only X axis
|
||||
REPEAT_Y, // Only Y axis
|
||||
REFLECT // Mirror the image
|
||||
};
|
||||
|
||||
enum class FillRule : int8_t {
|
||||
|
@ -33,7 +33,7 @@ bool
|
||||
gfxSurfaceDrawable::DrawWithSamplingRect(gfxContext* aContext,
|
||||
const gfxRect& aFillRect,
|
||||
const gfxRect& aSamplingRect,
|
||||
bool aRepeat,
|
||||
ExtendMode aExtendMode,
|
||||
const Filter& aFilter,
|
||||
gfxFloat aOpacity)
|
||||
{
|
||||
@ -52,23 +52,24 @@ gfxSurfaceDrawable::DrawWithSamplingRect(gfxContext* aContext,
|
||||
return false;
|
||||
}
|
||||
|
||||
DrawInternal(aContext, aFillRect, intRect, false, aFilter, aOpacity, gfxMatrix());
|
||||
DrawInternal(aContext, aFillRect, intRect, ExtendMode::CLAMP, aFilter, aOpacity, gfxMatrix());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
gfxSurfaceDrawable::Draw(gfxContext* aContext,
|
||||
const gfxRect& aFillRect,
|
||||
bool aRepeat,
|
||||
ExtendMode aExtendMode,
|
||||
const Filter& aFilter,
|
||||
gfxFloat aOpacity,
|
||||
const gfxMatrix& aTransform)
|
||||
|
||||
{
|
||||
if (!mSourceSurface) {
|
||||
return true;
|
||||
}
|
||||
|
||||
DrawInternal(aContext, aFillRect, IntRect(), aRepeat, aFilter, aOpacity, aTransform);
|
||||
DrawInternal(aContext, aFillRect, IntRect(), aExtendMode, aFilter, aOpacity, aTransform);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -76,21 +77,15 @@ void
|
||||
gfxSurfaceDrawable::DrawInternal(gfxContext* aContext,
|
||||
const gfxRect& aFillRect,
|
||||
const IntRect& aSamplingRect,
|
||||
bool aRepeat,
|
||||
ExtendMode aExtendMode,
|
||||
const Filter& aFilter,
|
||||
gfxFloat aOpacity,
|
||||
const gfxMatrix& aTransform)
|
||||
{
|
||||
ExtendMode extend = ExtendMode::CLAMP;
|
||||
|
||||
if (aRepeat) {
|
||||
extend = ExtendMode::REPEAT;
|
||||
}
|
||||
|
||||
Matrix patternTransform = ToMatrix(aTransform * mTransform);
|
||||
patternTransform.Invert();
|
||||
|
||||
SurfacePattern pattern(mSourceSurface, extend,
|
||||
SurfacePattern pattern(mSourceSurface, aExtendMode,
|
||||
patternTransform, aFilter, aSamplingRect);
|
||||
|
||||
Rect fillRect = ToRect(aFillRect);
|
||||
@ -127,7 +122,7 @@ gfxCallbackDrawable::MakeSurfaceDrawable(const Filter aFilter)
|
||||
return nullptr;
|
||||
|
||||
RefPtr<gfxContext> ctx = new gfxContext(dt);
|
||||
Draw(ctx, gfxRect(0, 0, mSize.width, mSize.height), false, aFilter);
|
||||
Draw(ctx, gfxRect(0, 0, mSize.width, mSize.height), ExtendMode::CLAMP, aFilter);
|
||||
|
||||
RefPtr<SourceSurface> surface = dt->Snapshot();
|
||||
if (surface) {
|
||||
@ -137,20 +132,33 @@ gfxCallbackDrawable::MakeSurfaceDrawable(const Filter aFilter)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsRepeatingExtendMode(ExtendMode aExtendMode)
|
||||
{
|
||||
switch (aExtendMode) {
|
||||
case ExtendMode::REPEAT:
|
||||
case ExtendMode::REPEAT_X:
|
||||
case ExtendMode::REPEAT_Y:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
gfxCallbackDrawable::Draw(gfxContext* aContext,
|
||||
const gfxRect& aFillRect,
|
||||
bool aRepeat,
|
||||
ExtendMode aExtendMode,
|
||||
const Filter& aFilter,
|
||||
gfxFloat aOpacity,
|
||||
const gfxMatrix& aTransform)
|
||||
{
|
||||
if ((aRepeat || aOpacity != 1.0) && !mSurfaceDrawable) {
|
||||
if ((IsRepeatingExtendMode(aExtendMode) || aOpacity != 1.0) && !mSurfaceDrawable) {
|
||||
mSurfaceDrawable = MakeSurfaceDrawable(aFilter);
|
||||
}
|
||||
|
||||
if (mSurfaceDrawable)
|
||||
return mSurfaceDrawable->Draw(aContext, aFillRect, aRepeat, aFilter,
|
||||
return mSurfaceDrawable->Draw(aContext, aFillRect, aExtendMode, aFilter,
|
||||
aOpacity, aTransform);
|
||||
|
||||
if (mCallback)
|
||||
@ -184,7 +192,7 @@ public:
|
||||
const Filter& aFilter,
|
||||
const gfxMatrix& aTransform = gfxMatrix())
|
||||
{
|
||||
return mDrawable->Draw(aContext, aFillRect, false, aFilter, 1.0,
|
||||
return mDrawable->Draw(aContext, aFillRect, ExtendMode::CLAMP, aFilter, 1.0,
|
||||
aTransform);
|
||||
}
|
||||
private:
|
||||
@ -204,7 +212,7 @@ gfxPatternDrawable::MakeCallbackDrawable()
|
||||
bool
|
||||
gfxPatternDrawable::Draw(gfxContext* aContext,
|
||||
const gfxRect& aFillRect,
|
||||
bool aRepeat,
|
||||
ExtendMode aExtendMode,
|
||||
const Filter& aFilter,
|
||||
gfxFloat aOpacity,
|
||||
const gfxMatrix& aTransform)
|
||||
@ -214,7 +222,7 @@ gfxPatternDrawable::Draw(gfxContext* aContext,
|
||||
if (!mPattern)
|
||||
return false;
|
||||
|
||||
if (aRepeat) {
|
||||
if (IsRepeatingExtendMode(aExtendMode)) {
|
||||
// We can't use mPattern directly: We want our repeated tiles to have
|
||||
// the size mSize, which might not be the case in mPattern.
|
||||
// So we need to draw mPattern into a surface of size mSize, create
|
||||
@ -223,7 +231,7 @@ gfxPatternDrawable::Draw(gfxContext* aContext,
|
||||
// those things, so we use them here. Drawing mPattern into the surface
|
||||
// will happen through this Draw() method with aRepeat = false.
|
||||
RefPtr<gfxCallbackDrawable> callbackDrawable = MakeCallbackDrawable();
|
||||
return callbackDrawable->Draw(aContext, aFillRect, true, aFilter,
|
||||
return callbackDrawable->Draw(aContext, aFillRect, aExtendMode, aFilter,
|
||||
aOpacity, aTransform);
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "gfxRect.h"
|
||||
#include "gfxMatrix.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/Types.h"
|
||||
|
||||
class gfxContext;
|
||||
class gfxPattern;
|
||||
@ -34,14 +35,15 @@ public:
|
||||
*/
|
||||
virtual bool Draw(gfxContext* aContext,
|
||||
const gfxRect& aFillRect,
|
||||
bool aRepeat,
|
||||
mozilla::gfx::ExtendMode aExtendMode,
|
||||
const mozilla::gfx::Filter& aFilter,
|
||||
gfxFloat aOpacity = 1.0,
|
||||
const gfxMatrix& aTransform = gfxMatrix()) = 0;
|
||||
|
||||
virtual bool DrawWithSamplingRect(gfxContext* aContext,
|
||||
const gfxRect& aFillRect,
|
||||
const gfxRect& aSamplingRect,
|
||||
bool aRepeat,
|
||||
mozilla::gfx::ExtendMode aExtendMode,
|
||||
const mozilla::gfx::Filter& aFilter,
|
||||
gfxFloat aOpacity = 1.0)
|
||||
{
|
||||
@ -69,22 +71,23 @@ public:
|
||||
|
||||
virtual bool Draw(gfxContext* aContext,
|
||||
const gfxRect& aFillRect,
|
||||
bool aRepeat,
|
||||
mozilla::gfx::ExtendMode aExtendMode,
|
||||
const mozilla::gfx::Filter& aFilter,
|
||||
gfxFloat aOpacity = 1.0,
|
||||
const gfxMatrix& aTransform = gfxMatrix());
|
||||
|
||||
virtual bool DrawWithSamplingRect(gfxContext* aContext,
|
||||
const gfxRect& aFillRect,
|
||||
const gfxRect& aSamplingRect,
|
||||
bool aRepeat,
|
||||
mozilla::gfx::ExtendMode aExtendMode,
|
||||
const mozilla::gfx::Filter& aFilter,
|
||||
gfxFloat aOpacity = 1.0);
|
||||
|
||||
|
||||
protected:
|
||||
void DrawInternal(gfxContext* aContext,
|
||||
const gfxRect& aFillRect,
|
||||
const mozilla::gfx::IntRect& aSamplingRect,
|
||||
bool aRepeat,
|
||||
mozilla::gfx::ExtendMode aExtendMode,
|
||||
const mozilla::gfx::Filter& aFilter,
|
||||
gfxFloat aOpacity,
|
||||
const gfxMatrix& aTransform = gfxMatrix());
|
||||
@ -129,7 +132,7 @@ public:
|
||||
|
||||
virtual bool Draw(gfxContext* aContext,
|
||||
const gfxRect& aFillRect,
|
||||
bool aRepeat,
|
||||
mozilla::gfx::ExtendMode aExtendMode,
|
||||
const mozilla::gfx::Filter& aFilter,
|
||||
gfxFloat aOpacity = 1.0,
|
||||
const gfxMatrix& aTransform = gfxMatrix());
|
||||
@ -153,11 +156,12 @@ public:
|
||||
|
||||
virtual bool Draw(gfxContext* aContext,
|
||||
const gfxRect& aFillRect,
|
||||
bool aRepeat,
|
||||
mozilla::gfx::ExtendMode aExtendMode,
|
||||
const mozilla::gfx::Filter& aFilter,
|
||||
gfxFloat aOpacity = 1.0,
|
||||
const gfxMatrix& aTransform = gfxMatrix());
|
||||
|
||||
|
||||
protected:
|
||||
already_AddRefed<gfxCallbackDrawable> MakeCallbackDrawable();
|
||||
|
||||
|
@ -459,7 +459,7 @@ CreateSamplingRestrictedDrawable(gfxDrawable* aDrawable,
|
||||
|
||||
RefPtr<gfxContext> tmpCtx = new gfxContext(target);
|
||||
tmpCtx->SetOp(OptimalFillOp());
|
||||
aDrawable->Draw(tmpCtx, needed - needed.TopLeft(), true, Filter::LINEAR,
|
||||
aDrawable->Draw(tmpCtx, needed - needed.TopLeft(), ExtendMode::REPEAT, Filter::LINEAR,
|
||||
1.0, gfxMatrix::Translation(needed.TopLeft()));
|
||||
RefPtr<SourceSurface> surface = target->Snapshot();
|
||||
|
||||
@ -683,7 +683,7 @@ PrescaleAndTileDrawable(gfxDrawable* aDrawable,
|
||||
RefPtr<gfxContext> tmpCtx = new gfxContext(scaledDT);
|
||||
scaledDT->SetTransform(ToMatrix(scaleMatrix));
|
||||
gfxRect gfxImageRect(aImageRect.x, aImageRect.y, aImageRect.width, aImageRect.height);
|
||||
aDrawable->Draw(tmpCtx, gfxImageRect, true, aFilter, 1.0, gfxMatrix());
|
||||
aDrawable->Draw(tmpCtx, gfxImageRect, ExtendMode::REPEAT, aFilter, 1.0, gfxMatrix());
|
||||
|
||||
RefPtr<SourceSurface> scaledImage = scaledDT->Snapshot();
|
||||
|
||||
@ -722,9 +722,7 @@ gfxUtils::DrawPixelSnapped(gfxContext* aContext,
|
||||
|
||||
gfxRect imageRect(gfxPoint(0, 0), aImageSize);
|
||||
gfxRect region(aRegion.Rect());
|
||||
|
||||
bool doTile = !imageRect.Contains(region) &&
|
||||
!(aImageFlags & imgIContainer::FLAG_CLAMP);
|
||||
ExtendMode extendMode = aRegion.GetExtendMode();
|
||||
|
||||
RefPtr<gfxASurface> currentTarget = aContext->CurrentSurface();
|
||||
gfxMatrix deviceSpaceToImageSpace = DeviceToImageTransform(aContext);
|
||||
@ -745,10 +743,11 @@ gfxUtils::DrawPixelSnapped(gfxContext* aContext,
|
||||
// translations, then we assume no resampling will occur so there's
|
||||
// nothing to do.
|
||||
// XXX if only we had source-clipping in cairo!
|
||||
|
||||
if (aContext->CurrentMatrix().HasNonIntegerTranslation()) {
|
||||
if (doTile || !aRegion.RestrictionContains(imageRect)) {
|
||||
if ((extendMode != ExtendMode::CLAMP) || !aRegion.RestrictionContains(imageRect)) {
|
||||
if (drawable->DrawWithSamplingRect(aContext, aRegion.Rect(), aRegion.Restriction(),
|
||||
doTile, aFilter, aOpacity)) {
|
||||
extendMode, aFilter, aOpacity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -773,13 +772,13 @@ gfxUtils::DrawPixelSnapped(gfxContext* aContext,
|
||||
// We no longer need to tile: Either we never needed to, or we already
|
||||
// filled a surface with the tiled pattern; this surface can now be
|
||||
// drawn without tiling.
|
||||
doTile = false;
|
||||
extendMode = ExtendMode::CLAMP;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
drawable->Draw(aContext, aRegion.Rect(), doTile, aFilter, aOpacity);
|
||||
drawable->Draw(aContext, aRegion.Rect(), extendMode, aFilter, aOpacity, gfxMatrix());
|
||||
}
|
||||
|
||||
/* static */ int
|
||||
|
@ -7,6 +7,7 @@
|
||||
#define mozilla_image_ImageRegion_h
|
||||
|
||||
#include "gfxRect.h"
|
||||
#include "mozilla/gfx/Types.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace image {
|
||||
@ -23,31 +24,37 @@ namespace image {
|
||||
*/
|
||||
class ImageRegion
|
||||
{
|
||||
typedef mozilla::gfx::ExtendMode ExtendMode;
|
||||
|
||||
public:
|
||||
static ImageRegion Empty()
|
||||
{
|
||||
return ImageRegion(gfxRect());
|
||||
return ImageRegion(gfxRect(), ExtendMode::CLAMP);
|
||||
}
|
||||
|
||||
static ImageRegion Create(const gfxRect& aRect)
|
||||
static ImageRegion Create(const gfxRect& aRect,
|
||||
ExtendMode aExtendMode = ExtendMode::CLAMP)
|
||||
{
|
||||
return ImageRegion(aRect);
|
||||
return ImageRegion(aRect, aExtendMode);
|
||||
}
|
||||
|
||||
static ImageRegion Create(const gfxSize& aSize)
|
||||
static ImageRegion Create(const gfxSize& aSize,
|
||||
ExtendMode aExtendMode = ExtendMode::CLAMP)
|
||||
{
|
||||
return ImageRegion(gfxRect(0, 0, aSize.width, aSize.height));
|
||||
return ImageRegion(gfxRect(0, 0, aSize.width, aSize.height), aExtendMode);
|
||||
}
|
||||
|
||||
static ImageRegion Create(const nsIntSize& aSize)
|
||||
static ImageRegion Create(const nsIntSize& aSize,
|
||||
ExtendMode aExtendMode = ExtendMode::CLAMP)
|
||||
{
|
||||
return ImageRegion(gfxRect(0, 0, aSize.width, aSize.height));
|
||||
return ImageRegion(gfxRect(0, 0, aSize.width, aSize.height), aExtendMode);
|
||||
}
|
||||
|
||||
static ImageRegion CreateWithSamplingRestriction(const gfxRect& aRect,
|
||||
const gfxRect& aRestriction)
|
||||
const gfxRect& aRestriction,
|
||||
ExtendMode aExtendMode = ExtendMode::CLAMP)
|
||||
{
|
||||
return ImageRegion(aRect, aRestriction);
|
||||
return ImageRegion(aRect, aRestriction, aExtendMode);
|
||||
}
|
||||
|
||||
bool IsRestricted() const { return mIsRestricted; }
|
||||
@ -133,22 +140,30 @@ public:
|
||||
return Create(mRect + aPt);
|
||||
}
|
||||
|
||||
gfx::ExtendMode GetExtendMode() const
|
||||
{
|
||||
return mExtendMode;
|
||||
}
|
||||
|
||||
/* ImageRegion() : mIsRestricted(false) { } */
|
||||
|
||||
private:
|
||||
explicit ImageRegion(const gfxRect& aRect)
|
||||
explicit ImageRegion(const gfxRect& aRect, ExtendMode aExtendMode)
|
||||
: mRect(aRect)
|
||||
, mExtendMode(aExtendMode)
|
||||
, mIsRestricted(false)
|
||||
{ }
|
||||
|
||||
ImageRegion(const gfxRect& aRect, const gfxRect& aRestriction)
|
||||
ImageRegion(const gfxRect& aRect, const gfxRect& aRestriction, ExtendMode aExtendMode)
|
||||
: mRect(aRect)
|
||||
, mRestriction(aRestriction)
|
||||
, mExtendMode(aExtendMode)
|
||||
, mIsRestricted(true)
|
||||
{ }
|
||||
|
||||
gfxRect mRect;
|
||||
gfxRect mRestriction;
|
||||
ExtendMode mExtendMode;
|
||||
bool mIsRestricted;
|
||||
};
|
||||
|
||||
|
@ -522,7 +522,7 @@ imgFrame::SurfaceForDrawing(bool aDoPadding,
|
||||
DrawOptions(1.0f, CompositionOp::OP_SOURCE));
|
||||
} else {
|
||||
SurfacePattern pattern(aSurface,
|
||||
ExtendMode::REPEAT,
|
||||
aRegion.GetExtendMode(),
|
||||
Matrix::Translation(mDecoded.x, mDecoded.y));
|
||||
target->FillRect(ToRect(aRegion.Intersect(available).Rect()), pattern);
|
||||
}
|
||||
@ -586,6 +586,7 @@ bool imgFrame::Draw(gfxContext* aContext, const ImageRegion& aRegion,
|
||||
gfxRect imageRect(0, 0, mImageSize.width, mImageSize.height);
|
||||
bool doTile = !imageRect.Contains(aRegion.Rect()) &&
|
||||
!(aImageFlags & imgIContainer::FLAG_CLAMP);
|
||||
|
||||
ImageRegion region(aRegion);
|
||||
// SurfaceForDrawing changes the current transform, and we need it to still
|
||||
// be changed when we call gfxUtils::DrawPixelSnapped. We still need to
|
||||
|
@ -3335,14 +3335,30 @@ nsCSSRendering::PrepareBackgroundLayer(nsPresContext* aPresContext,
|
||||
state.mFillArea = state.mDestArea;
|
||||
int repeatX = aLayer.mRepeat.mXRepeat;
|
||||
int repeatY = aLayer.mRepeat.mYRepeat;
|
||||
|
||||
ExtendMode repeatMode = ExtendMode::CLAMP;
|
||||
if (repeatX == NS_STYLE_BG_REPEAT_REPEAT) {
|
||||
state.mFillArea.x = bgClipRect.x;
|
||||
state.mFillArea.width = bgClipRect.width;
|
||||
repeatMode = ExtendMode::REPEAT_X;
|
||||
}
|
||||
if (repeatY == NS_STYLE_BG_REPEAT_REPEAT) {
|
||||
state.mFillArea.y = bgClipRect.y;
|
||||
state.mFillArea.height = bgClipRect.height;
|
||||
|
||||
/***
|
||||
* We're repeating on the X axis already,
|
||||
* so if we have to repeat in the Y axis,
|
||||
* we really need to repeat in both directions.
|
||||
*/
|
||||
if (repeatMode == ExtendMode::REPEAT_X) {
|
||||
repeatMode = ExtendMode::REPEAT;
|
||||
} else {
|
||||
repeatMode = ExtendMode::REPEAT_Y;
|
||||
}
|
||||
}
|
||||
state.mImageRenderer.SetExtendMode(repeatMode);
|
||||
|
||||
state.mFillArea.IntersectRect(state.mFillArea, bgClipRect);
|
||||
|
||||
state.mCompositionOp = GetGFXBlendMode(aLayer.mBlendMode);
|
||||
@ -4648,6 +4664,7 @@ nsImageRenderer::nsImageRenderer(nsIFrame* aForFrame,
|
||||
, mPrepareResult(DrawResult::NOT_READY)
|
||||
, mSize(0, 0)
|
||||
, mFlags(aFlags)
|
||||
, mExtendMode(ExtendMode::CLAMP)
|
||||
{
|
||||
}
|
||||
|
||||
@ -5036,7 +5053,8 @@ nsImageRenderer::Draw(nsPresContext* aPresContext,
|
||||
aPresContext,
|
||||
mImageContainer, imageSize, filter,
|
||||
aDest, aFill, aAnchor, aDirtyRect,
|
||||
ConvertImageRendererToDrawFlags(mFlags));
|
||||
ConvertImageRendererToDrawFlags(mFlags),
|
||||
mExtendMode);
|
||||
}
|
||||
case eStyleImageType_Gradient:
|
||||
{
|
||||
|
@ -261,6 +261,7 @@ public:
|
||||
|
||||
bool IsReady() const { return mPrepareResult == DrawResult::SUCCESS; }
|
||||
DrawResult PrepareResult() const { return mPrepareResult; }
|
||||
void SetExtendMode(mozilla::gfx::ExtendMode aMode) { mExtendMode = aMode; }
|
||||
|
||||
private:
|
||||
/**
|
||||
@ -297,6 +298,7 @@ private:
|
||||
DrawResult mPrepareResult;
|
||||
nsSize mSize; // unscaled size of the image, in app units
|
||||
uint32_t mFlags;
|
||||
mozilla::gfx::ExtendMode mExtendMode;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -6219,7 +6219,8 @@ ComputeSnappedImageDrawingParameters(gfxContext* aCtx,
|
||||
const nsRect aDirty,
|
||||
imgIContainer* aImage,
|
||||
Filter aGraphicsFilter,
|
||||
uint32_t aImageFlags)
|
||||
uint32_t aImageFlags,
|
||||
ExtendMode aExtendMode)
|
||||
{
|
||||
if (aDest.IsEmpty() || aFill.IsEmpty())
|
||||
return SnappedImageDrawingParameters();
|
||||
@ -6388,8 +6389,17 @@ ComputeSnappedImageDrawingParameters(gfxContext* aCtx,
|
||||
transform = transform * currentMatrix;
|
||||
}
|
||||
|
||||
ExtendMode extendMode = (aImageFlags & imgIContainer::FLAG_CLAMP)
|
||||
? ExtendMode::CLAMP
|
||||
: aExtendMode;
|
||||
// We were passed in the default extend mode but need to tile.
|
||||
if (extendMode == ExtendMode::CLAMP && doTile) {
|
||||
MOZ_ASSERT(!(aImageFlags & imgIContainer::FLAG_CLAMP));
|
||||
extendMode = ExtendMode::REPEAT;
|
||||
}
|
||||
|
||||
ImageRegion region =
|
||||
ImageRegion::CreateWithSamplingRestriction(imageSpaceFill, subimage);
|
||||
ImageRegion::CreateWithSamplingRestriction(imageSpaceFill, subimage, extendMode);
|
||||
|
||||
return SnappedImageDrawingParameters(transform, intImageSize,
|
||||
region, svgViewportSize);
|
||||
@ -6406,7 +6416,8 @@ DrawImageInternal(gfxContext& aContext,
|
||||
const nsPoint& aAnchor,
|
||||
const nsRect& aDirty,
|
||||
const SVGImageContext* aSVGContext,
|
||||
uint32_t aImageFlags)
|
||||
uint32_t aImageFlags,
|
||||
ExtendMode aExtendMode = ExtendMode::CLAMP)
|
||||
{
|
||||
DrawResult result = DrawResult::SUCCESS;
|
||||
|
||||
@ -6424,7 +6435,7 @@ DrawImageInternal(gfxContext& aContext,
|
||||
SnappedImageDrawingParameters params =
|
||||
ComputeSnappedImageDrawingParameters(&aContext, appUnitsPerDevPixel, aDest,
|
||||
aFill, aAnchor, aDirty, aImage,
|
||||
aGraphicsFilter, aImageFlags);
|
||||
aGraphicsFilter, aImageFlags, aExtendMode);
|
||||
|
||||
if (!params.shouldDraw) {
|
||||
return result;
|
||||
@ -6634,7 +6645,8 @@ nsLayoutUtils::DrawBackgroundImage(gfxContext& aContext,
|
||||
const nsRect& aFill,
|
||||
const nsPoint& aAnchor,
|
||||
const nsRect& aDirty,
|
||||
uint32_t aImageFlags)
|
||||
uint32_t aImageFlags,
|
||||
ExtendMode aExtendMode)
|
||||
{
|
||||
PROFILER_LABEL("layout", "nsLayoutUtils::DrawBackgroundImage",
|
||||
js::ProfileEntry::Category::GRAPHICS);
|
||||
@ -6647,7 +6659,7 @@ nsLayoutUtils::DrawBackgroundImage(gfxContext& aContext,
|
||||
|
||||
return DrawImageInternal(aContext, aPresContext, aImage,
|
||||
aGraphicsFilter, aDest, aFill, aAnchor,
|
||||
aDirty, &svgContext, aImageFlags);
|
||||
aDirty, &svgContext, aImageFlags, aExtendMode);
|
||||
}
|
||||
|
||||
/* static */ DrawResult
|
||||
|
@ -119,6 +119,7 @@ class nsLayoutUtils
|
||||
typedef mozilla::gfx::SourceSurface SourceSurface;
|
||||
typedef mozilla::gfx::Color Color;
|
||||
typedef mozilla::gfx::DrawTarget DrawTarget;
|
||||
typedef mozilla::gfx::ExtendMode ExtendMode;
|
||||
typedef mozilla::gfx::Filter Filter;
|
||||
typedef mozilla::gfx::Float Float;
|
||||
typedef mozilla::gfx::Point Point;
|
||||
@ -1769,7 +1770,8 @@ public:
|
||||
* @param aAnchor A point in aFill which we will ensure is
|
||||
* pixel-aligned in the output.
|
||||
* @param aDirty Pixels outside this area may be skipped.
|
||||
* @param aImageFlags Image flags of the imgIContainer::FLAG_* variety
|
||||
* @param aImageFlags Image flags of the imgIContainer::FLAG_* variety.
|
||||
* @param aExtendMode How to extend the image over the dest rect.
|
||||
*/
|
||||
static DrawResult DrawBackgroundImage(gfxContext& aContext,
|
||||
nsPresContext* aPresContext,
|
||||
@ -1780,7 +1782,8 @@ public:
|
||||
const nsRect& aFill,
|
||||
const nsPoint& aAnchor,
|
||||
const nsRect& aDirty,
|
||||
uint32_t aImageFlags);
|
||||
uint32_t aImageFlags,
|
||||
ExtendMode aExtendMode);
|
||||
|
||||
/**
|
||||
* Draw an image.
|
||||
|
Loading…
Reference in New Issue
Block a user