Bug 702878: Extend gfx::2d API and D2D backend with new functionality. r=jrmuizel sr=roc

This commit is contained in:
Bas Schouten 2011-12-28 03:51:38 +01:00
parent a5c6a574f5
commit c30eae6661
12 changed files with 446 additions and 82 deletions

View File

@ -809,7 +809,7 @@ protected:
if (state.patternStyles[aStyle]->mRepeat == nsCanvasPatternAzure::NOREPEAT) {
mode = EXTEND_CLAMP;
} else {
mode = EXTEND_WRAP;
mode = EXTEND_REPEAT;
}
mPattern = new (mSurfacePattern.addr())
SurfacePattern(state.patternStyles[aStyle]->mSurface, mode);

View File

@ -148,13 +148,19 @@ struct StrokeOptions {
*
* mFilter - Filter used when resampling source surface region to the
* destination region.
* aSamplingBounds - This indicates whether the implementation is allowed
* to sample pixels outside the source rectangle as
* specified in DrawSurface on the surface.
*/
struct DrawSurfaceOptions {
DrawSurfaceOptions(Filter aFilter = FILTER_LINEAR)
DrawSurfaceOptions(Filter aFilter = FILTER_LINEAR,
SamplingBounds aSamplingBounds = SAMPLING_UNBOUNDED)
: mFilter(aFilter)
, mSamplingBounds(aSamplingBounds)
{ }
Filter mFilter : 3;
SamplingBounds mSamplingBounds : 1;
};
/*
@ -212,16 +218,20 @@ class LinearGradientPattern : public Pattern
public:
/*
* aBegin Start of the linear gradient
* aEnd End of the linear gradient
* aEnd End of the linear gradient - NOTE: In the case of a zero length
* gradient it will act as the color of the last stop.
* aStops GradientStops object for this gradient, this should match the
* backend type of the draw target this pattern will be used with.
* aMatrix A matrix that transforms the pattern into user space
*/
LinearGradientPattern(const Point &aBegin,
const Point &aEnd,
GradientStops *aStops)
GradientStops *aStops,
const Matrix &aMatrix = Matrix())
: mBegin(aBegin)
, mEnd(aEnd)
, mStops(aStops)
, mMatrix(aMatrix)
{
}
@ -230,6 +240,7 @@ public:
Point mBegin;
Point mEnd;
RefPtr<GradientStops> mStops;
Matrix mMatrix;
};
/*
@ -245,17 +256,20 @@ public:
* aEnd End of the linear gradient
* aStops GradientStops object for this gradient, this should match the
* backend type of the draw target this pattern will be used with.
* aMatrix A matrix that transforms the pattern into user space
*/
RadialGradientPattern(const Point &aCenter1,
const Point &aCenter2,
Float aRadius1,
Float aRadius2,
GradientStops *aStops)
GradientStops *aStops,
const Matrix &aMatrix = Matrix())
: mCenter1(aCenter1)
, mCenter2(aCenter2)
, mRadius1(aRadius1)
, mRadius2(aRadius2)
, mStops(aStops)
, mMatrix(aMatrix)
{
}
@ -266,6 +280,7 @@ public:
Float mRadius1;
Float mRadius2;
RefPtr<GradientStops> mStops;
Matrix mMatrix;
};
/*
@ -275,9 +290,19 @@ public:
class SurfacePattern : public Pattern
{
public:
SurfacePattern(SourceSurface *aSourceSurface, ExtendMode aExtendMode)
/*
* aSourceSurface Surface to use for drawing
* aExtendMode This determines how the image is extended outside the bounds
* of the image.
* aMatrix A matrix that transforms the pattern into user space
* aFilter Resampling filter used for resampling the image.
*/
SurfacePattern(SourceSurface *aSourceSurface, ExtendMode aExtendMode,
const Matrix &aMatrix = Matrix(), Filter aFilter = FILTER_LINEAR)
: mSurface(aSourceSurface)
, mExtendMode(aExtendMode)
, mFilter(aFilter)
, mMatrix(aMatrix)
{}
virtual PatternType GetType() const { return PATTERN_SURFACE; }
@ -285,6 +310,7 @@ public:
RefPtr<SourceSurface> mSurface;
ExtendMode mExtendMode;
Filter mFilter;
Matrix mMatrix;
};
/*
@ -311,6 +337,7 @@ public:
class DataSourceSurface : public SourceSurface
{
public:
virtual SurfaceType GetType() const { return SURFACE_DATA; }
/* Get the raw bitmap data of the surface */
virtual unsigned char *GetData() = 0;
/*
@ -319,6 +346,12 @@ public:
*/
virtual int32_t Stride() = 0;
/*
* This function is called after modifying the data on the source surface
* directly through the data pointer.
*/
virtual void MarkDirty() {}
virtual TemporaryRef<DataSourceSurface> GetDataSurface() { RefPtr<DataSourceSurface> temp = this; return temp.forget(); }
};
@ -606,6 +639,19 @@ public:
const Pattern &aPattern,
const DrawOptions &aOptions = DrawOptions()) = 0;
/*
* This takes a source pattern and a mask, and composites the source pattern
* onto the destination surface using the alpha channel of the mask pattern
* as a mask for the operation.
*
* aSource Source pattern
* aMask Mask pattern
* aOptions Drawing options
*/
virtual void Mask(const Pattern &aSource,
const Pattern &aMask,
const DrawOptions &aOptions = DrawOptions()) = 0;
/*
* Push a clip to the DrawTarget.
*
@ -613,6 +659,14 @@ public:
*/
virtual void PushClip(const Path *aPath) = 0;
/*
* Push an axis-aligned rectangular clip to the DrawTarget. This rectangle
* is specified in user space.
*
* aRect The rect to clip to
*/
virtual void PushClipRect(const Rect &aRect) = 0;
/* Pop a clip from the DrawTarget. A pop without a corresponding push will
* be ignored.
*/
@ -625,9 +679,9 @@ public:
* The SourceSurface does not take ownership of aData, and may be freed at any time.
*/
virtual TemporaryRef<SourceSurface> CreateSourceSurfaceFromData(unsigned char *aData,
const IntSize &aSize,
int32_t aStride,
SurfaceFormat aFormat) const = 0;
const IntSize &aSize,
int32_t aStride,
SurfaceFormat aFormat) const = 0;
/*
* Create a SourceSurface optimized for use with this DrawTarget from
@ -666,8 +720,13 @@ public:
*
* aStops An array of gradient stops
* aNumStops Number of stops in the array aStops
* aExtendNone This describes how to extend the stop color outside of the
* gradient area.
*/
virtual TemporaryRef<GradientStops> CreateGradientStops(GradientStop *aStops, uint32_t aNumStops) const = 0;
virtual TemporaryRef<GradientStops>
CreateGradientStops(GradientStop *aStops,
uint32_t aNumStops,
ExtendMode aExtendMode = EXTEND_CLAMP) const = 0;
const Matrix &GetTransform() const { return mTransform; }
@ -695,12 +754,34 @@ protected:
class Factory
{
public:
#ifdef USE_CAIRO
static TemporaryRef<DrawTarget> CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface);
#endif
static TemporaryRef<DrawTarget> CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat);
static TemporaryRef<ScaledFont> CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSize);
static TemporaryRef<DrawTarget>
CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat);
static TemporaryRef<DrawTarget>
CreateDrawTargetForData(BackendType aBackend, unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat);
static TemporaryRef<ScaledFont>
CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSize);
/*
* This creates a simple data source surface for a certain size. It allocates
* new memory for the surface. This memory is freed when the surface is
* destroyed.
*/
static TemporaryRef<DataSourceSurface>
CreateDataSourceSurface(const IntSize &aSize, SurfaceFormat aFormat);
/*
* This creates a simple data source surface for some existing data. It will
* wrap this data and the data for this source surface. The caller is
* responsible for deallocating the memory only after destruction of the
* surface.
*/
static TemporaryRef<DataSourceSurface>
CreateDataSourceSurfaceFromData(unsigned char *aData, int32_t aStride,
const IntSize &aSize, SurfaceFormat aFormat);
#ifdef WIN32
static TemporaryRef<DrawTarget> CreateDrawTargetForD3D10Texture(ID3D10Texture2D *aTexture, SurfaceFormat aFormat);

View File

@ -106,8 +106,13 @@ public:
const Pattern &aPattern,
const DrawOptions &aOptions)
{ return; }
virtual void Mask(const Pattern &aSource,
const Pattern &aMask,
const DrawOptions &aOptions = DrawOptions())
{ return; }
virtual void PushClip(const Path *aPath) { }
virtual void PushClipRect(const Rect &aRect) { }
virtual void PopClip() { }
virtual TemporaryRef<PathBuilder> CreatePathBuilder(FillRule aFillRule = FILL_WINDING) const { return NULL; }
@ -123,7 +128,7 @@ public:
CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const
{ return NULL; }
virtual TemporaryRef<GradientStops> CreateGradientStops(GradientStop *aStops, uint32_t aNumStops) const
virtual TemporaryRef<GradientStops> CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, ExtendMode aExtendMode = EXTEND_CLAMP) const
{ return NULL; }
virtual void *GetNativeSurface(NativeSurfaceType aType)

View File

@ -268,6 +268,8 @@ DrawTargetD2D::DrawSurface(SourceSurface *aSurface,
PrepareForDrawing(rt);
rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
Rect srcRect = aSource;
switch (aSurface->GetType()) {
@ -753,6 +755,8 @@ DrawTargetD2D::FillRect(const Rect &aRect,
PrepareForDrawing(rt);
rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
if (brush) {
@ -772,6 +776,8 @@ DrawTargetD2D::StrokeRect(const Rect &aRect,
PrepareForDrawing(rt);
rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions);
@ -794,6 +800,8 @@ DrawTargetD2D::StrokeLine(const Point &aStart,
PrepareForDrawing(rt);
rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions);
@ -822,6 +830,8 @@ DrawTargetD2D::Stroke(const Path *aPath,
PrepareForDrawing(rt);
rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions);
@ -849,6 +859,8 @@ DrawTargetD2D::Fill(const Path *aPath,
PrepareForDrawing(rt);
rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
if (brush) {
@ -916,6 +928,36 @@ DrawTargetD2D::FillGlyphs(ScaledFont *aFont,
FinalizeRTForOperation(aOptions.mCompositionOp, aPattern, Rect(0, 0, (Float)mSize.width, (Float)mSize.height));
}
void
DrawTargetD2D::Mask(const Pattern &aSource,
const Pattern &aMask,
const DrawOptions &aOptions)
{
ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, aSource);
PrepareForDrawing(rt);
RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aSource, aOptions.mAlpha);
RefPtr<ID2D1Brush> maskBrush = CreateBrushForPattern(aMask, 1.0f);
RefPtr<ID2D1Layer> layer;
rt->CreateLayer(byRef(layer));
rt->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), NULL,
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
D2D1::IdentityMatrix(),
1.0f, maskBrush),
layer);
Rect rect(0, 0, mSize.width, mSize.height);
Matrix mat = mTransform;
mat.Invert();
rt->FillRectangle(D2DRect(mat.TransformBounds(rect)), brush);
rt->PopLayer();
FinalizeRTForOperation(aOptions.mCompositionOp, aSource, Rect(0, 0, (Float)mSize.width, (Float)mSize.height));
}
void
DrawTargetD2D::PushClip(const Path *aPath)
{
@ -957,11 +999,45 @@ DrawTargetD2D::PushClip(const Path *aPath)
}
}
void
DrawTargetD2D::PushClipRect(const Rect &aRect)
{
if (!mTransform.IsRectilinear()) {
// Whoops, this isn't a rectangle in device space, Direct2D will not deal
// with this transform the way we want it to.
// See remarks: http://msdn.microsoft.com/en-us/library/dd316860%28VS.85%29.aspx
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
pathBuilder->MoveTo(aRect.TopLeft());
pathBuilder->LineTo(aRect.TopRight());
pathBuilder->LineTo(aRect.BottomRight());
pathBuilder->LineTo(aRect.BottomLeft());
pathBuilder->Close();
RefPtr<Path> path = pathBuilder->Finish();
return PushClip(path);
}
PushedClip clip;
// Do not store the transform, just store the device space rectangle directly.
clip.mBounds = D2DRect(mTransform.TransformBounds(aRect));
mPushedClips.push_back(clip);
mRT->SetTransform(D2D1::IdentityMatrix());
if (mClipsArePushed) {
mRT->PushAxisAlignedClip(clip.mBounds, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
}
}
void
DrawTargetD2D::PopClip()
{
if (mClipsArePushed) {
mRT->PopLayer();
if (mPushedClips.back().mLayer) {
mRT->PopLayer();
} else {
mRT->PopAxisAlignedClip();
}
}
mPushedClips.pop_back();
}
@ -975,7 +1051,6 @@ DrawTargetD2D::CreateSourceSurfaceFromData(unsigned char *aData,
RefPtr<SourceSurfaceD2D> newSurf = new SourceSurfaceD2D();
if (!newSurf->InitFromData(aData, aSize, aStride, aFormat, mRT)) {
gfxDebug() << *this << ": Failure to create source surface from data. Size: " << aSize;
return NULL;
}
@ -1049,9 +1124,9 @@ DrawTargetD2D::CreatePathBuilder(FillRule aFillRule) const
}
TemporaryRef<GradientStops>
DrawTargetD2D::CreateGradientStops(GradientStop *rawStops, uint32_t aNumStops) const
DrawTargetD2D::CreateGradientStops(GradientStop *rawStops, uint32_t aNumStops, ExtendMode aExtendMode) const
{
D2D1_GRADIENT_STOP *stops = new D2D1_GRADIENT_STOP[aNumStops];
vector<D2D1_GRADIENT_STOP> stops(aNumStops);
for (uint32_t i = 0; i < aNumStops; i++) {
stops[i].position = rawStops[i].offset;
@ -1060,7 +1135,10 @@ DrawTargetD2D::CreateGradientStops(GradientStop *rawStops, uint32_t aNumStops) c
RefPtr<ID2D1GradientStopCollection> stopCollection;
HRESULT hr = mRT->CreateGradientStopCollection(stops, aNumStops, byRef(stopCollection));
HRESULT hr =
mRT->CreateGradientStopCollection(&stops.front(), aNumStops,
D2D1_GAMMA_2_2, D2DExtend(aExtendMode),
byRef(stopCollection));
if (FAILED(hr)) {
gfxWarning() << "Failed to create GradientStopCollection. Code: " << hr;
@ -1097,7 +1175,7 @@ DrawTargetD2D::Init(const IntSize &aSize, SurfaceFormat aFormat)
}
mDevice = Factory::GetDirect3D10Device();
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
CD3D10_TEXTURE2D_DESC desc(DXGIFormat(aFormat),
mSize.width,
mSize.height,
1, 1);
@ -1110,7 +1188,12 @@ DrawTargetD2D::Init(const IntSize &aSize, SurfaceFormat aFormat)
return false;
}
return InitD2DRenderTarget();
if (!InitD2DRenderTarget()) {
return false;
}
mRT->Clear(D2D1::ColorF(0, 0));
return true;
}
bool
@ -1230,8 +1313,6 @@ DrawTargetD2D::InitD2DRenderTarget()
mRT->BeginDraw();
mRT->Clear(D2D1::ColorF(0, 0));
if (mFormat == FORMAT_B8G8R8X8) {
mRT->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE);
}
@ -1246,23 +1327,30 @@ DrawTargetD2D::PrepareForDrawing(ID2D1RenderTarget *aRT)
if (mPushedClips.size()) {
// The transform of clips is relative to the world matrix, since we use the total
// transform for the clips, make the world matrix identity.
mRT->SetTransform(D2D1::IdentityMatrix());
mTransformDirty = true;
for (std::vector<PushedClip>::iterator iter = mPushedClips.begin();
iter != mPushedClips.end(); iter++) {
D2D1_LAYER_OPTIONS options = D2D1_LAYER_OPTIONS_NONE;
if (mFormat == FORMAT_B8G8R8X8) {
options = D2D1_LAYER_OPTIONS_INITIALIZE_FOR_CLEARTYPE;
}
aRT->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), iter->mPath->mGeometry,
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
iter->mTransform, 1.0f, NULL,
options), iter->mLayer);
}
aRT->SetTransform(D2D1::IdentityMatrix());
if (aRT == mRT) {
mClipsArePushed = true;
mTransformDirty = true;
}
for (std::vector<PushedClip>::iterator iter = mPushedClips.begin();
iter != mPushedClips.end(); iter++) {
D2D1_LAYER_OPTIONS options = D2D1_LAYER_OPTIONS_NONE;
if (iter->mLayer) {
D2D1_LAYER_OPTIONS options = D2D1_LAYER_OPTIONS_NONE;
if (mFormat == FORMAT_B8G8R8X8) {
options = D2D1_LAYER_OPTIONS_INITIALIZE_FOR_CLEARTYPE;
if (mFormat == FORMAT_B8G8R8X8) {
options = D2D1_LAYER_OPTIONS_INITIALIZE_FOR_CLEARTYPE;
}
aRT->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), iter->mPath->mGeometry,
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
iter->mTransform, 1.0f, NULL,
options), iter->mLayer);
} else {
aRT->PushAxisAlignedClip(iter->mBounds, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
}
}
}
}
}
@ -1421,8 +1509,12 @@ DrawTargetD2D::FinalizeRTForOperation(CompositionOp aOperator, const Pattern &aP
return;
}
for (unsigned int i = 0; i < mPushedClips.size(); i++) {
mTempRT->PopLayer();
for (int i = mPushedClips.size() - 1; i >= 0; i--) {
if (mPushedClips[i].mLayer) {
mTempRT->PopLayer();
} else {
mTempRT->PopAxisAlignedClip();
}
}
mRT->Flush();
@ -1535,7 +1627,7 @@ DrawTargetD2D::CreateRTForTexture(ID3D10Texture2D *aTexture)
D2D1_ALPHA_MODE alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
if (mFormat == FORMAT_B8G8R8X8) {
if (mFormat == FORMAT_B8G8R8X8 && aTexture == mTexture) {
alphaMode = D2D1_ALPHA_MODE_IGNORE;
}
@ -1592,8 +1684,12 @@ void
DrawTargetD2D::PopAllClips()
{
if (mClipsArePushed) {
for (unsigned int i = 0; i < mPushedClips.size(); i++) {
mRT->PopLayer();
for (int i = mPushedClips.size() - 1; i >= 0; i--) {
if (mPushedClips[i].mLayer) {
mRT->PopLayer();
} else {
mRT->PopAxisAlignedClip();
}
}
mClipsArePushed = false;
@ -1629,9 +1725,20 @@ DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
return NULL;
}
if (pat->mBegin == pat->mEnd) {
RefPtr<ID2D1SolidColorBrush> colBrush;
uint32_t stopCount = stops->mStopCollection->GetGradientStopCount();
vector<D2D1_GRADIENT_STOP> d2dStops(stopCount);
stops->mStopCollection->GetGradientStops(&d2dStops.front(), stopCount);
mRT->CreateSolidColorBrush(d2dStops.back().color,
D2D1::BrushProperties(aAlpha),
byRef(colBrush));
return colBrush;
}
mRT->CreateLinearGradientBrush(D2D1::LinearGradientBrushProperties(D2DPoint(pat->mBegin),
D2DPoint(pat->mEnd)),
D2D1::BrushProperties(aAlpha),
D2D1::BrushProperties(aAlpha, D2DMatrix(pat->mMatrix)),
stops->mStopCollection,
byRef(gradBrush));
return gradBrush;
@ -1652,7 +1759,7 @@ DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
D2D1::RadialGradientBrushProperties(D2DPoint(pat->mCenter1),
D2D1::Point2F(),
pat->mRadius2, pat->mRadius2),
D2D1::BrushProperties(aAlpha),
D2D1::BrushProperties(aAlpha, D2DMatrix(pat->mMatrix)),
stops->mStopCollection,
byRef(gradBrush));
@ -1668,6 +1775,8 @@ DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
}
RefPtr<ID2D1Bitmap> bitmap;
Matrix mat = pat->mMatrix;
switch (pat->mSurface->GetType()) {
case SURFACE_D2D1_BITMAP:
@ -1677,8 +1786,11 @@ DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
bitmap = surf->mBitmap;
if (!bitmap) {
gfxDebug() << "Source surface used for pattern too large!";
return NULL;
bitmap = CreatePartialBitmapForSurface(surf, mat);
if (!bitmap) {
return NULL;
}
}
}
break;
@ -1691,22 +1803,12 @@ DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
}
break;
}
D2D1_EXTEND_MODE extend = D2D1_EXTEND_MODE_CLAMP;
switch (pat->mExtendMode) {
case EXTEND_WRAP:
extend = D2D1_EXTEND_MODE_WRAP;
break;
case EXTEND_MIRROR:
extend = D2D1_EXTEND_MODE_MIRROR;
break;
}
mRT->CreateBitmapBrush(bitmap,
D2D1::BitmapBrushProperties(extend,
extend,
D2D1::BitmapBrushProperties(D2DExtend(pat->mExtendMode),
D2DExtend(pat->mExtendMode),
D2DFilter(pat->mFilter)),
D2D1::BrushProperties(aAlpha),
D2D1::BrushProperties(aAlpha, D2DMatrix(mat)),
byRef(bmBrush));
return bmBrush;
@ -1855,6 +1957,59 @@ DrawTargetD2D::CreateGradientTexture(const GradientStopsD2D *aStops)
return tex;
}
TemporaryRef<ID2D1Bitmap>
DrawTargetD2D::CreatePartialBitmapForSurface(SourceSurfaceD2D *aSurface, Matrix &aMatrix)
{
RefPtr<ID2D1Bitmap> bitmap;
// This is where things get complicated. The source surface was
// created for a surface that was too large to fit in a texture.
// We'll need to figure out if we can work with a partial upload
// or downsample in software.
Matrix transform = mTransform;
transform = aMatrix * transform;
if (!transform.Invert()) {
// Singular transform, nothing to be drawn.
return NULL;
}
Rect rect(0, 0, mSize.width, mSize.height);
// Calculate the rectangle of the source mapped to our surface.
rect = transform.TransformBounds(rect);
rect.RoundOut();
Rect uploadRect(0, 0, aSurface->mSize.width, aSurface->mSize.height);
// Calculate the rectangle on the source bitmap that touches our
// surface.
uploadRect = uploadRect.Intersect(rect);
if (uploadRect.width <= mRT->GetMaximumBitmapSize() &&
uploadRect.height <= mRT->GetMaximumBitmapSize()) {
int Bpp = BytesPerPixel(aSurface->mFormat);
int stride = Bpp * aSurface->mSize.width;
// A partial upload will suffice.
mRT->CreateBitmap(D2D1::SizeU(uint32_t(uploadRect.width), uint32_t(uploadRect.height)),
&aSurface->mRawData.front() + int(uploadRect.x) + int(uploadRect.y) * stride,
stride,
D2D1::BitmapProperties(D2DPixelFormat(aSurface->mFormat)),
byRef(bitmap));
aMatrix.Translate(-uploadRect.x, -uploadRect.y);
return bitmap;
} else {
// XXX - FIX ME!!
MOZ_ASSERT(false);
gfxDebug() << "Source surface used for pattern too large!";
return NULL;
}
}
void
DrawTargetD2D::SetupEffectForRadialGradient(const RadialGradientPattern *aPattern)
{
@ -1907,13 +2062,26 @@ DrawTargetD2D::SetupEffectForRadialGradient(const RadialGradientPattern *aPatter
AsMatrix()->SetMatrix(matrix);
float A = dc.x * dc.x + dc.y * dc.y - dr * dr;
uint32_t offset = 0;
switch (stops->mStopCollection->GetExtendMode()) {
case D2D1_EXTEND_MODE_WRAP:
offset = 1;
break;
case D2D1_EXTEND_MODE_MIRROR:
offset = 2;
break;
default:
gfxWarning() << "This shouldn't happen! Invalid extend mode for gradient stops.";
}
if (A == 0) {
mPrivateData->mEffect->GetTechniqueByName("SampleRadialGradient")->
GetPassByIndex(1)->Apply(0);
GetPassByIndex(offset * 2 + 1)->Apply(0);
} else {
mPrivateData->mEffect->GetVariableByName("A")->AsScalar()->SetFloat(A);
mPrivateData->mEffect->GetTechniqueByName("SampleRadialGradient")->
GetPassByIndex(0)->Apply(0);
GetPassByIndex(offset * 2)->Apply(0);
}
}
@ -1936,7 +2104,7 @@ DrawTargetD2D::factory()
D2D1_FACTORY_OPTIONS options;
#ifdef _DEBUG
options.debugLevel = D2D1_DEBUG_LEVEL_NONE;
options.debugLevel = D2D1_DEBUG_LEVEL_WARNING;
#else
options.debugLevel = D2D1_DEBUG_LEVEL_NONE;
#endif

View File

@ -56,6 +56,7 @@ namespace mozilla {
namespace gfx {
class SourceSurfaceD2DTarget;
class SourceSurfaceD2D;
class GradientStopsD2D;
struct PrivateD3D10DataD2D
@ -117,7 +118,11 @@ public:
const GlyphBuffer &aBuffer,
const Pattern &aPattern,
const DrawOptions &aOptions = DrawOptions());
virtual void Mask(const Pattern &aSource,
const Pattern &aMask,
const DrawOptions &aOptions = DrawOptions());
virtual void PushClip(const Path *aPath);
virtual void PushClipRect(const Rect &aRect);
virtual void PopClip();
virtual TemporaryRef<SourceSurface> CreateSourceSurfaceFromData(unsigned char *aData,
@ -134,7 +139,10 @@ public:
virtual TemporaryRef<PathBuilder> CreatePathBuilder(FillRule aFillRule = FILL_WINDING) const;
virtual TemporaryRef<GradientStops> CreateGradientStops(GradientStop *aStops, uint32_t aNumStops) const;
virtual TemporaryRef<GradientStops>
CreateGradientStops(GradientStop *aStops,
uint32_t aNumStops,
ExtendMode aExtendMode = EXTEND_CLAMP) const;
virtual void *GetNativeSurface(NativeSurfaceType aType);
@ -186,6 +194,11 @@ private:
TemporaryRef<ID3D10Texture1D> CreateGradientTexture(const GradientStopsD2D *aStops);
// This creates a partially uploaded bitmap for a SourceSurfaceD2D that is
// too big to fit in a bitmap. It adjusts the passed Matrix to accomodate the
// partial upload.
TemporaryRef<ID2D1Bitmap> CreatePartialBitmapForSurface(SourceSurfaceD2D *aSurface, Matrix &aMatrix);
void SetupEffectForRadialGradient(const RadialGradientPattern *aPattern);
static const uint32_t test = 4;

View File

@ -199,9 +199,9 @@ ExtendModeToTileMode(ExtendMode aMode)
{
case EXTEND_CLAMP:
return SkShader::kClamp_TileMode;
case EXTEND_WRAP:
case EXTEND_REPEAT:
return SkShader::kRepeat_TileMode;
case EXTEND_MIRROR:
case EXTEND_REFLECT:
return SkShader::kMirror_TileMode;
}
return SkShader::kClamp_TileMode;
@ -671,7 +671,7 @@ DrawTargetSkia::PopClip()
}
TemporaryRef<GradientStops>
DrawTargetSkia::CreateGradientStops(GradientStop *aStops, uint32_t aNumStops) const
DrawTargetSkia::CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, ExtendMode aExtendMode) const
{
std::vector<GradientStop> stops;
stops.resize(aNumStops);

View File

@ -99,7 +99,12 @@ public:
const GlyphBuffer &aBuffer,
const Pattern &aPattern,
const DrawOptions &aOptions = DrawOptions());
virtual void Mask(const Pattern &aSource,
const Pattern &aMask,
const DrawOptions &aOptions = DrawOptions())
{ return; }
virtual void PushClip(const Path *aPath);
virtual void PushClipRect(const Rect &aRect) { }
virtual void PopClip();
virtual TemporaryRef<SourceSurface> CreateSourceSurfaceFromData(unsigned char *aData,
const IntSize &aSize,
@ -111,7 +116,7 @@ public:
virtual TemporaryRef<DrawTarget>
CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const;
virtual TemporaryRef<PathBuilder> CreatePathBuilder(FillRule aFillRule = FILL_WINDING) const;
virtual TemporaryRef<GradientStops> CreateGradientStops(GradientStop *aStops, uint32_t aNumStops) const;
virtual TemporaryRef<GradientStops> CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, ExtendMode aExtendMode = EXTEND_CLAMP) const;
virtual void SetTransform(const Matrix &aTransform);
bool Init(const IntSize &aSize, SurfaceFormat aFormat);

View File

@ -59,6 +59,21 @@ static inline D2D1_RECT_F D2DRect(const Rect &aRect)
return D2D1::RectF(aRect.x, aRect.y, aRect.XMost(), aRect.YMost());
}
static inline D2D1_EXTEND_MODE D2DExtend(ExtendMode aExtendMode)
{
D2D1_EXTEND_MODE extend = D2D1_EXTEND_MODE_CLAMP;
switch (aExtendMode) {
case EXTEND_REPEAT:
extend = D2D1_EXTEND_MODE_WRAP;
break;
case EXTEND_REFLECT:
extend = D2D1_EXTEND_MODE_MIRROR;
break;
}
return extend;
}
static inline D2D1_BITMAP_INTERPOLATION_MODE D2DFilter(const Filter &aFilter)
{
switch (aFilter) {
@ -69,11 +84,11 @@ static inline D2D1_BITMAP_INTERPOLATION_MODE D2DFilter(const Filter &aFilter)
return D2D1_BITMAP_INTERPOLATION_MODE_LINEAR;
}
static inline D2D1_ANTIALIAS_MODE D2DAAMode(const AntialiasMode &aMode)
static inline D2D1_ANTIALIAS_MODE D2DAAMode(AntialiasMode aMode)
{
switch (aMode) {
case AA_NONE:
D2D1_ANTIALIAS_MODE_ALIASED;
return D2D1_ANTIALIAS_MODE_ALIASED;
}
return D2D1_ANTIALIAS_MODE_PER_PRIMITIVE;
@ -141,6 +156,11 @@ static inline D2D1_ALPHA_MODE AlphaMode(SurfaceFormat aFormat)
return D2D1_ALPHA_MODE_PREMULTIPLIED;
}
static inline D2D1_PIXEL_FORMAT D2DPixelFormat(SurfaceFormat aFormat)
{
return D2D1::PixelFormat(DXGIFormat(aFormat), AlphaMode(aFormat));
}
static inline int BytesPerPixel(SurfaceFormat aFormat)
{
switch (aFormat) {

View File

@ -143,6 +143,24 @@ public:
return resultMatrix;
}
/* Returns true if the matrix is a rectilinear transformation (i.e.
* grid-aligned rectangles are transformed to grid-aligned rectangles)
*/
bool IsRectilinear() {
if (FuzzyEqual(_12, 0) && FuzzyEqual(_21, 0)) {
return true;
} else if (FuzzyEqual(_22, 0) && FuzzyEqual(_11, 0)) {
return true;
}
return false;
}
private:
static bool FuzzyEqual(Float aV1, Float aV2) {
// XXX - Check if fabs does the smart thing and just negates the sign bit.
return fabs(aV2 - aV1) < 1e-6;
}
};
}

View File

@ -60,6 +60,20 @@ sampler sSampler = sampler_state {
AddressV = Clamp;
};
sampler sWrapSampler = sampler_state {
Filter = MIN_MAG_MIP_LINEAR;
Texture = tex;
AddressU = Wrap;
AddressV = Wrap;
};
sampler sMirrorSampler = sampler_state {
Filter = MIN_MAG_MIP_LINEAR;
Texture = tex;
AddressU = Mirror;
AddressV = Mirror;
};
sampler sMaskSampler = sampler_state {
Filter = MIN_MAG_MIP_LINEAR;
Texture = mask;
@ -142,7 +156,7 @@ float4 SampleMaskTexturePS( VS_OUTPUT In) : SV_Target
return tex.Sample(sSampler, In.TexCoord) * mask.Sample(sMaskSampler, In.MaskTexCoord).a;
};
float4 SampleRadialGradientPS( VS_RADIAL_OUTPUT In) : SV_Target
float4 SampleRadialGradientPS(VS_RADIAL_OUTPUT In, uniform sampler aSampler) : SV_Target
{
// Radial gradient painting is defined as the set of circles whose centers
// are described by C(t) = (C2 - C1) * t + C1; with radii
@ -178,7 +192,7 @@ float4 SampleRadialGradientPS( VS_RADIAL_OUTPUT In) : SV_Target
float upper_t = lerp(t.y, t.x, isValid.x);
float4 output = tex.Sample(sSampler, float2(upper_t, 0.5));
float4 output = tex.Sample(aSampler, float2(upper_t, 0.5));
// Premultiply
output.rgb *= output.a;
// Multiply the output color by the input mask for the operation.
@ -186,7 +200,7 @@ float4 SampleRadialGradientPS( VS_RADIAL_OUTPUT In) : SV_Target
return output;
};
float4 SampleRadialGradientA0PS( VS_RADIAL_OUTPUT In) : SV_Target
float4 SampleRadialGradientA0PS( VS_RADIAL_OUTPUT In, uniform sampler aSampler ) : SV_Target
{
// This simpler shader is used for the degenerate case where A is 0,
// i.e. we're actually solving a linear equation.
@ -205,7 +219,7 @@ float4 SampleRadialGradientA0PS( VS_RADIAL_OUTPUT In) : SV_Target
return float4(0, 0, 0, 0);
}
float4 output = tex.Sample(sSampler, float2(t, 0.5));
float4 output = tex.Sample(aSampler, float2(t, 0.5));
// Premultiply
output.rgb *= output.a;
// Multiply the output color by the input mask for the operation.
@ -277,19 +291,47 @@ technique10 SampleTexture
technique10 SampleRadialGradient
{
pass P0
pass APos
{
SetRasterizerState(TextureRast);
SetVertexShader(CompileShader(vs_4_0_level_9_3, SampleRadialVS()));
SetGeometryShader(NULL);
SetPixelShader(CompileShader(ps_4_0_level_9_3, SampleRadialGradientPS()));
SetPixelShader(CompileShader(ps_4_0_level_9_3, SampleRadialGradientPS( sSampler )));
}
pass P1
pass A0
{
SetRasterizerState(TextureRast);
SetVertexShader(CompileShader(vs_4_0_level_9_3, SampleRadialVS()));
SetGeometryShader(NULL);
SetPixelShader(CompileShader(ps_4_0_level_9_3, SampleRadialGradientA0PS()));
SetPixelShader(CompileShader(ps_4_0_level_9_3, SampleRadialGradientA0PS( sSampler )));
}
pass APosWrap
{
SetRasterizerState(TextureRast);
SetVertexShader(CompileShader(vs_4_0_level_9_3, SampleRadialVS()));
SetGeometryShader(NULL);
SetPixelShader(CompileShader(ps_4_0_level_9_3, SampleRadialGradientPS( sWrapSampler )));
}
pass A0Wrap
{
SetRasterizerState(TextureRast);
SetVertexShader(CompileShader(vs_4_0_level_9_3, SampleRadialVS()));
SetGeometryShader(NULL);
SetPixelShader(CompileShader(ps_4_0_level_9_3, SampleRadialGradientA0PS( sWrapSampler )));
}
pass APosMirror
{
SetRasterizerState(TextureRast);
SetVertexShader(CompileShader(vs_4_0_level_9_3, SampleRadialVS()));
SetGeometryShader(NULL);
SetPixelShader(CompileShader(ps_4_0_level_9_3, SampleRadialGradientPS( sMirrorSampler )));
}
pass A0Mirror
{
SetRasterizerState(TextureRast);
SetVertexShader(CompileShader(vs_4_0_level_9_3, SampleRadialVS()));
SetGeometryShader(NULL);
SetPixelShader(CompileShader(ps_4_0_level_9_3, SampleRadialGradientA0PS( sMirrorSampler )));
}
}

View File

@ -160,6 +160,16 @@ SourceSurfaceD2DTarget::GetBitmap(ID2D1RenderTarget *aRT)
hr = aRT->CreateSharedBitmap(IID_IDXGISurface, surf, &props, byRef(mBitmap));
if (FAILED(hr)) {
// This seems to happen for FORMAT_A8 sometimes...
aRT->CreateBitmap(D2D1::SizeU(desc.Width, desc.Height),
D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(mFormat),
AlphaMode(mFormat))),
byRef(mBitmap));
if (mDrawTarget) {
mBitmap->CopyFromRenderTarget(NULL, mDrawTarget->mRT, NULL);
return mBitmap;
}
gfxWarning() << "Failed to create shared bitmap for DrawTarget snapshot. Code: " << hr;
return NULL;
}

View File

@ -53,6 +53,7 @@ enum SurfaceType
SURFACE_D2D1_BITMAP, /* Surface wrapping a ID2D1Bitmap */
SURFACE_D2D1_DRAWTARGET, /* Surface made from a D2D draw target */
SURFACE_CAIRO, /* Surface wrapping a cairo surface */
SURFACE_CAIRO_IMAGE, /* Data surface wrapping a cairo image surface */
SURFACE_COREGRAPHICS_IMAGE, /* Surface wrapping a CoreGraphics Image */
SURFACE_SKIA /* Surface wrapping a Skia bitmap */
};
@ -95,7 +96,7 @@ enum NativeFontType
};
enum CompositionOp { OP_OVER, OP_ADD, OP_ATOP, OP_OUT, OP_IN, OP_SOURCE, OP_DEST_IN, OP_DEST_OUT, OP_DEST_OVER, OP_DEST_ATOP, OP_XOR, OP_COUNT };
enum ExtendMode { EXTEND_CLAMP, EXTEND_WRAP, EXTEND_MIRROR };
enum ExtendMode { EXTEND_CLAMP, EXTEND_REPEAT, EXTEND_REFLECT };
enum FillRule { FILL_WINDING, FILL_EVEN_ODD };
enum AntialiasMode { AA_NONE, AA_GRAY, AA_SUBPIXEL };
enum Snapping { SNAP_NONE, SNAP_ALIGNED };
@ -103,6 +104,7 @@ enum Filter { FILTER_LINEAR, FILTER_POINT };
enum PatternType { PATTERN_COLOR, PATTERN_SURFACE, PATTERN_LINEAR_GRADIENT, PATTERN_RADIAL_GRADIENT };
enum JoinStyle { JOIN_BEVEL, JOIN_ROUND, JOIN_MITER, JOIN_MITER_OR_BEVEL };
enum CapStyle { CAP_BUTT, CAP_ROUND, CAP_SQUARE };
enum SamplingBounds { SAMPLING_UNBOUNDED, SAMPLING_BOUNDED };
/* Color is stored in non-premultiplied form */
struct Color