Backout bug 580786 / bug 716639 / bug 692879 / bug 717921 / bug 692879 (2dc5909e63b0:ced751d32df6); a=philor

This commit is contained in:
Ms2ger 2012-01-17 10:48:19 +01:00
parent 834bc5acc7
commit ce301744c0
39 changed files with 216 additions and 2106 deletions

View File

@ -1165,10 +1165,8 @@ nsCanvasRenderingContext2DAzure::Redraw()
return NS_OK;
}
if (!mThebesSurface)
mThebesSurface =
gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mTarget);
mThebesSurface->MarkDirty();
if (mThebesSurface)
mThebesSurface->MarkDirty();
nsSVGEffects::InvalidateDirectRenderingObservers(HTMLCanvasElement());
@ -1197,10 +1195,8 @@ nsCanvasRenderingContext2DAzure::Redraw(const mgfx::Rect &r)
return;
}
if (!mThebesSurface)
mThebesSurface =
gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mTarget);
mThebesSurface->MarkDirty();
if (mThebesSurface)
mThebesSurface->MarkDirty();
nsSVGEffects::InvalidateDirectRenderingObservers(HTMLCanvasElement());

View File

@ -18,23 +18,6 @@ function IsD2DEnabled() {
return enabled;
}
function IsMacOSX10_5orOlder() {
var is105orOlder = false;
if (navigator.platform.indexOf("Mac") == 0) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var version = Components.classes["@mozilla.org/system-info;1"]
.getService(Components.interfaces.nsIPropertyBag2)
.getProperty("version");
// the next line is correct: Mac OS 10.6 corresponds to Darwin version 10 !
// Mac OS 10.5 would be Darwin version 9. the |version| string we've got here
// is the Darwin version.
is105orOlder = (parseFloat(version) < 10.0);
}
return is105orOlder;
}
function IsAzureEnabled() {
var enabled = false;
@ -5795,12 +5778,10 @@ function test_2d_gradient_interpolate_overlap() {
var canvas = document.getElementById('c215');
var ctx = canvas.getContext('2d');
if (!IsD2DEnabled() && !IsMacOSX10_5orOlder()) {
// On D2D the different nature of how gradients
if (!IsD2DEnabled()) {
// Only run this on non-D2D. On D2D the different nature of how gradients
// are drawn makes it so we cannot guarantee these stops are completely
// hard.
// On OS X 10.5 quartz is confused by the overlapping stops: Bug #715235
canvas.width = 200;
var g = ctx.createLinearGradient(0, 0, 200, 0);
g.addColorStop(0, '#f00');
@ -5854,15 +5835,12 @@ for (var p = 0; p < ps.length; ++p)
}
ctx.fillStyle = g;
ctx.fillRect(0, 0, 100, 50);
isPixel(ctx, 1,25, 0,255,0,255, 0);
isPixel(ctx, 30,25, 0,255,0,255, 0);
isPixel(ctx, 40,25, 0,255,0,255, 0);
isPixel(ctx, 60,25, 0,255,0,255, 0);
isPixel(ctx, 80,25, 0,255,0,255, 0);
if (!IsMacOSX10_5orOlder()) {
// On OS X 10.5 quartz is confused by the overlapping stops: Bug #715235
isPixel(ctx, 1,25, 0,255,0,255, 0);
isPixel(ctx, 30,25, 0,255,0,255, 0);
isPixel(ctx, 40,25, 0,255,0,255, 0);
isPixel(ctx, 60,25, 0,255,0,255, 0);
isPixel(ctx, 80,25, 0,255,0,255, 0);
}
}
</script>

View File

@ -41,7 +41,7 @@
#include "Point.h"
#include "Rect.h"
#include "Matrix.h"
#include "UserData.h"
// This RefPtr class isn't ideal for usage in Azure, as it doesn't allow T**
// outparams using the &-operator. But it will have to do as there's no easy
// solution.
@ -744,14 +744,7 @@ public:
*/
virtual void *GetNativeSurface(NativeSurfaceType aType) { return NULL; }
void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) {
mUserData.Add(key, userData, destroy);
}
void *GetUserData(UserDataKey *key) {
return mUserData.Get(key);
}
protected:
UserData mUserData;
Matrix mTransform;
bool mTransformDirty : 1;

View File

@ -19,7 +19,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Jeff Muizelaar <jmuizelaar@mozilla.com>
* Bas Schouten <bschouten@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -37,9 +37,6 @@
#include "DrawTargetCG.h"
#include "SourceSurfaceCG.h"
#include "Rect.h"
#include "ScaledFontMac.h"
#include "Tools.h"
#include <vector>
//CG_EXTERN void CGContextSetCompositeOperation (CGContextRef, PrivateCGCompositeMode);
@ -51,11 +48,6 @@ static CGRect RectToCGRect(Rect r)
return CGRectMake(r.x, r.y, r.width, r.height);
}
static CGRect IntRectToCGRect(IntRect r)
{
return CGRectMake(r.x, r.y, r.width, r.height);
}
CGBlendMode ToBlendMode(CompositionOp op)
{
CGBlendMode mode;
@ -63,40 +55,18 @@ CGBlendMode ToBlendMode(CompositionOp op)
case OP_OVER:
mode = kCGBlendModeNormal;
break;
case OP_SOURCE:
mode = kCGBlendModeCopy;
break;
case OP_CLEAR:
mode = kCGBlendModeClear;
break;
case OP_ADD:
mode = kCGBlendModePlusLighter;
break;
case OP_ATOP:
mode = kCGBlendModeSourceAtop;
break;
case OP_OUT:
mode = kCGBlendModeSourceOut;
break;
case OP_IN:
mode = kCGBlendModeSourceIn;
break;
case OP_SOURCE:
mode = kCGBlendModeCopy;
break;
case OP_DEST_IN:
mode = kCGBlendModeDestinationIn;
break;
case OP_DEST_OUT:
mode = kCGBlendModeDestinationOut;
break;
case OP_DEST_OVER:
mode = kCGBlendModeDestinationOver;
break;
case OP_DEST_ATOP:
mode = kCGBlendModeDestinationAtop;
break;
case OP_XOR:
mode = kCGBlendModeXOR;
break;
/*
case OP_CLEAR:
mode = kCGBlendModeClear;
break;*/
default:
mode = kCGBlendModeNormal;
}
@ -111,31 +81,12 @@ DrawTargetCG::DrawTargetCG()
DrawTargetCG::~DrawTargetCG()
{
// We need to conditionally release these because Init can fail without initializing these.
if (mColorSpace)
CGColorSpaceRelease(mColorSpace);
if (mCg)
CGContextRelease(mCg);
}
TemporaryRef<SourceSurface>
DrawTargetCG::Snapshot()
{
RefPtr<SourceSurfaceCG> newSurf = new SourceSurfaceCG(CGBitmapContextCreateImage(mCg));
return newSurf;
}
TemporaryRef<DrawTarget>
DrawTargetCG::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const
{
// XXX: in thebes we use CGLayers to do this kind of thing. It probably makes sense
// to add that in somehow, but at a higher level
RefPtr<DrawTargetCG> newTarget = new DrawTargetCG();
if (newTarget->Init(aSize, aFormat)) {
return newTarget;
} else {
return NULL;
}
return NULL;
}
TemporaryRef<SourceSurface>
@ -146,7 +97,7 @@ DrawTargetCG::CreateSourceSurfaceFromData(unsigned char *aData,
{
RefPtr<SourceSurfaceCG> newSurf = new SourceSurfaceCG();
if (!newSurf->InitFromData(aData, aSize, aStride, aFormat)) {
if (!newSurf->InitFromData(aData, aSize, aStride, aFormat)) {
return NULL;
}
@ -159,67 +110,16 @@ DrawTargetCG::OptimizeSourceSurface(SourceSurface *aSurface) const
return NULL;
}
class UnboundnessFixer
{
CGRect mClipBounds;
CGLayerRef mLayer;
CGContextRef mCg;
public:
UnboundnessFixer() : mCg(NULL) {}
CGContextRef Check(CGContextRef baseCg, CompositionOp blend)
{
if (!IsOperatorBoundByMask(blend)) {
mClipBounds = CGContextGetClipBoundingBox(baseCg);
// TransparencyLayers aren't blended using the blend mode so
// we are forced to use CGLayers
//XXX: The size here is in default user space units, of the layer relative to the graphics context.
// is the clip bounds still correct if, for example, we have a scale applied to the context?
mLayer = CGLayerCreateWithContext(baseCg, mClipBounds.size, NULL);
mCg = CGLayerGetContext(mLayer);
// CGContext's default to have the origin at the bottom left
// so flip it to the top left and adjust for the origin
// of the layer
CGContextTranslateCTM(mCg, -mClipBounds.origin.x, mClipBounds.origin.y + mClipBounds.size.height);
CGContextScaleCTM(mCg, 1, -1);
return mCg;
} else {
return baseCg;
}
}
void Fix(CGContextRef baseCg)
{
if (mCg) {
CGContextTranslateCTM(baseCg, 0, mClipBounds.size.height);
CGContextScaleCTM(baseCg, 1, -1);
mClipBounds.origin.y *= -1;
CGContextDrawLayerAtPoint(baseCg, mClipBounds.origin, mLayer);
CGContextRelease(mCg);
}
}
};
void
DrawTargetCG::DrawSurface(SourceSurface *aSurface,
const Rect &aDest,
const Rect &aSource,
const DrawSurfaceOptions &aSurfOptions,
const DrawOptions &aDrawOptions)
const DrawOptions &aOptions,
const DrawSurfaceOptions &aSurfOptions)
{
CGImageRef image;
CGImageRef subimage = NULL;
if (aSurface->GetType() == SURFACE_COREGRAPHICS_IMAGE) {
CGContextSaveGState(mCg);
CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp));
UnboundnessFixer fixer;
CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp);
CGContextSetAlpha(cg, aDrawOptions.mAlpha);
CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform));
if (aSurface->GetType() == COREGRAPHICS_IMAGE) {
image = static_cast<SourceSurfaceCG*>(aSurface)->GetImage();
/* we have two options here:
* - create a subimage -- this is slower
@ -229,737 +129,56 @@ DrawTargetCG::DrawSurface(SourceSurface *aSurface,
image = subimage;
}
CGContextScaleCTM(cg, 1, -1);
CGRect flippedRect = CGRectMake(aDest.x, -(aDest.y + aDest.height),
aDest.width, aDest.height);
//XXX: we should implement this for patterns too
if (aSurfOptions.mFilter == FILTER_POINT)
CGContextSetInterpolationQuality(cg, kCGInterpolationNone);
CGContextDrawImage(cg, flippedRect, image);
fixer.Fix(mCg);
CGContextRestoreGState(mCg);
CGContextDrawImage(mCg, RectToCGRect(aDest), image);
CGImageRelease(subimage);
}
}
static CGColorRef ColorToCGColor(CGColorSpaceRef aColorSpace, const Color& aColor)
{
CGFloat components[4] = {aColor.r, aColor.g, aColor.b, aColor.a};
return CGColorCreate(aColorSpace, components);
}
class GradientStopsCG : public GradientStops
{
public:
//XXX: The skia backend uses a vector and passes in aNumStops. It should do better
GradientStopsCG(GradientStop* aStops, uint32_t aNumStops, ExtendMode aExtendMode)
{
//XXX: do the stops need to be in any particular order?
// what should we do about the color space here? we certainly shouldn't be
// recreating it all the time
std::vector<CGFloat> colors;
std::vector<CGFloat> offsets;
colors.reserve(aNumStops*4);
offsets.reserve(aNumStops);
for (uint32_t i = 0; i < aNumStops; i++) {
colors.push_back(aStops[i].color.r);
colors.push_back(aStops[i].color.g);
colors.push_back(aStops[i].color.b);
colors.push_back(aStops[i].color.a);
offsets.push_back(aStops[i].offset);
}
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
mGradient = CGGradientCreateWithColorComponents(colorSpace,
&colors.front(),
&offsets.front(),
aNumStops);
CGColorSpaceRelease(colorSpace);
}
virtual ~GradientStopsCG() {
CGGradientRelease(mGradient);
}
BackendType GetBackendType() const { return BACKEND_COREGRAPHICS; }
CGGradientRef mGradient;
};
TemporaryRef<GradientStops>
DrawTargetCG::CreateGradientStops(GradientStop *aStops, uint32_t aNumStops,
ExtendMode aExtendMode) const
{
return new GradientStopsCG(aStops, aNumStops, aExtendMode);
}
static void
DrawGradient(CGContextRef cg, const Pattern &aPattern)
{
if (aPattern.GetType() == PATTERN_LINEAR_GRADIENT) {
const LinearGradientPattern& pat = static_cast<const LinearGradientPattern&>(aPattern);
GradientStopsCG *stops = static_cast<GradientStopsCG*>(pat.mStops.get());
// XXX: we should take the m out of the properties of LinearGradientPatterns
CGPoint startPoint = { pat.mBegin.x, pat.mBegin.y };
CGPoint endPoint = { pat.mEnd.x, pat.mEnd.y };
// Canvas spec states that we should avoid drawing degenerate gradients (XXX: should this be in common code?)
//if (startPoint.x == endPoint.x && startPoint.y == endPoint.y)
// return;
CGContextDrawLinearGradient(cg, stops->mGradient, startPoint, endPoint,
kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
} else if (aPattern.GetType() == PATTERN_RADIAL_GRADIENT) {
const RadialGradientPattern& pat = static_cast<const RadialGradientPattern&>(aPattern);
GradientStopsCG *stops = static_cast<GradientStopsCG*>(pat.mStops.get());
// XXX: we should take the m out of the properties of RadialGradientPatterns
CGPoint startCenter = { pat.mCenter1.x, pat.mCenter1.y };
CGFloat startRadius = pat.mRadius1;
CGPoint endCenter = { pat.mCenter2.x, pat.mCenter2.y };
CGFloat endRadius = pat.mRadius2;
//XXX: are there degenerate radial gradients that we should avoid drawing?
CGContextDrawRadialGradient(cg, stops->mGradient, startCenter, startRadius, endCenter, endRadius,
kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
} else {
assert(0);
}
}
static void
drawPattern(void *info, CGContextRef context)
{
CGImageRef image = static_cast<CGImageRef>(info);
CGRect rect = {{0, 0},
{static_cast<CGFloat>(CGImageGetWidth(image)),
static_cast<CGFloat>(CGImageGetHeight(image))}};
CGContextDrawImage(context, rect, image);
}
static void
releaseInfo(void *info)
{
CGImageRef image = static_cast<CGImageRef>(info);
CGImageRelease(image);
}
CGPatternCallbacks patternCallbacks = {
0,
drawPattern,
releaseInfo
};
static bool
isGradient(const Pattern &aPattern)
{
return aPattern.GetType() == PATTERN_LINEAR_GRADIENT || aPattern.GetType() == PATTERN_RADIAL_GRADIENT;
}
/* CoreGraphics patterns ignore the userspace transform so
* we need to multiply it in */
static CGPatternRef
CreateCGPattern(const Pattern &aPattern, CGAffineTransform aUserSpace)
{
const SurfacePattern& pat = static_cast<const SurfacePattern&>(aPattern);
// XXX: is .get correct here?
CGImageRef image = static_cast<SourceSurfaceCG*>(pat.mSurface.get())->GetImage();
CGFloat xStep, yStep;
switch (pat.mExtendMode) {
case EXTEND_CLAMP:
// The 1 << 22 comes from Webkit see Pattern::createPlatformPattern() in PatternCG.cpp for more info
xStep = static_cast<CGFloat>(1 << 22);
yStep = static_cast<CGFloat>(1 << 22);
break;
case EXTEND_REFLECT:
assert(0);
case EXTEND_REPEAT:
xStep = static_cast<CGFloat>(CGImageGetWidth(image));
yStep = static_cast<CGFloat>(CGImageGetHeight(image));
// webkit uses wkCGPatternCreateWithImageAndTransform a wrapper around CGPatternCreateWithImage2
// this is done to avoid pixel-cracking along pattern boundaries
// (see https://bugs.webkit.org/show_bug.cgi?id=53055)
// typedef enum {
// wkPatternTilingNoDistortion,
// wkPatternTilingConstantSpacingMinimalDistortion,
// wkPatternTilingConstantSpacing
// } wkPatternTiling;
// extern CGPatternRef (*wkCGPatternCreateWithImageAndTransform)(CGImageRef, CGAffineTransform, int);
}
//XXX: We should be using CGContextDrawTiledImage when we can. Even though it
// creates a pattern, it seems to go down a faster path than using a delegate
// like we do below
CGRect bounds = {
{0, 0,},
{static_cast<CGFloat>(CGImageGetWidth(image)), static_cast<CGFloat>(CGImageGetHeight(image))}
};
CGAffineTransform transform = CGAffineTransformConcat(CGAffineTransformMakeScale(1, -1), aUserSpace);
transform = CGAffineTransformTranslate(transform, 0, -static_cast<float>(CGImageGetHeight(image)));
return CGPatternCreate(CGImageRetain(image), bounds, transform, xStep, yStep, kCGPatternTilingConstantSpacing,
true, &patternCallbacks);
}
static void
SetFillFromPattern(CGContextRef cg, CGColorSpaceRef aColorSpace, const Pattern &aPattern)
{
assert(!isGradient(aPattern));
if (aPattern.GetType() == PATTERN_COLOR) {
const Color& color = static_cast<const ColorPattern&>(aPattern).mColor;
//XXX: we should cache colors
CGColorRef cgcolor = ColorToCGColor(aColorSpace, color);
CGContextSetFillColorWithColor(cg, cgcolor);
CGColorRelease(cgcolor);
} else if (aPattern.GetType() == PATTERN_SURFACE) {
CGColorSpaceRef patternSpace;
patternSpace = CGColorSpaceCreatePattern (NULL);
CGContextSetFillColorSpace(cg, patternSpace);
CGColorSpaceRelease(patternSpace);
CGPatternRef pattern = CreateCGPattern(aPattern, CGContextGetCTM(cg));
CGFloat alpha = 1.;
CGContextSetFillPattern(cg, pattern, &alpha);
CGPatternRelease(pattern);
}
}
static void
SetStrokeFromPattern(CGContextRef cg, CGColorSpaceRef aColorSpace, const Pattern &aPattern)
{
assert(!isGradient(aPattern));
if (aPattern.GetType() == PATTERN_COLOR) {
const Color& color = static_cast<const ColorPattern&>(aPattern).mColor;
//XXX: we should cache colors
CGColorRef cgcolor = ColorToCGColor(aColorSpace, color);
CGContextSetStrokeColorWithColor(cg, cgcolor);
CGColorRelease(cgcolor);
} else if (aPattern.GetType() == PATTERN_SURFACE) {
CGColorSpaceRef patternSpace;
patternSpace = CGColorSpaceCreatePattern (NULL);
CGContextSetStrokeColorSpace(cg, patternSpace);
CGColorSpaceRelease(patternSpace);
CGPatternRef pattern = CreateCGPattern(aPattern, CGContextGetCTM(cg));
CGFloat alpha = 1.;
CGContextSetStrokePattern(cg, pattern, &alpha);
CGPatternRelease(pattern);
}
}
void
DrawTargetCG::FillRect(const Rect &aRect,
const Pattern &aPattern,
const DrawOptions &aDrawOptions)
const DrawOptions &aOptions)
{
CGContextSaveGState(mCg);
UnboundnessFixer fixer;
CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp);
CGContextSetAlpha(mCg, aDrawOptions.mAlpha);
CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp));
CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform));
if (isGradient(aPattern)) {
CGContextClipToRect(cg, RectToCGRect(aRect));
DrawGradient(cg, aPattern);
} else {
SetFillFromPattern(cg, mColorSpace, aPattern);
CGContextFillRect(cg, RectToCGRect(aRect));
//XXX: it would be nice to hang a CGColor off of the pattern here
if (aPattern.GetType() == COLOR) {
Color color = static_cast<const ColorPattern*>(&aPattern)->mColor;
//XXX: the m prefixes are painful here
CGContextSetRGBFillColor(mCg, color.mR, color.mG, color.mB, color.mA);
}
fixer.Fix(mCg);
CGContextRestoreGState(mCg);
CGContextSetBlendMode(mCg, ToBlendMode(aOptions.mCompositionOp));
CGContextFillRect(mCg, RectToCGRect(aRect));
}
void
DrawTargetCG::StrokeLine(const Point &p1, const Point &p2, const Pattern &aPattern, const StrokeOptions &aStrokeOptions, const DrawOptions &aDrawOptions)
{
CGContextSaveGState(mCg);
UnboundnessFixer fixer;
CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp);
CGContextSetAlpha(mCg, aDrawOptions.mAlpha);
CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp));
CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform));
CGContextBeginPath(cg);
CGContextMoveToPoint(cg, p1.x, p1.y);
CGContextAddLineToPoint(cg, p2.x, p2.y);
SetStrokeOptions(cg, aStrokeOptions);
if (isGradient(aPattern)) {
CGContextReplacePathWithStrokedPath(cg);
//XXX: should we use EO clip here?
CGContextClip(cg);
DrawGradient(cg, aPattern);
} else {
SetStrokeFromPattern(cg, mColorSpace, aPattern);
CGContextStrokePath(cg);
}
fixer.Fix(mCg);
CGContextRestoreGState(mCg);
}
void
DrawTargetCG::StrokeRect(const Rect &aRect,
const Pattern &aPattern,
const StrokeOptions &aStrokeOptions,
const DrawOptions &aDrawOptions)
{
CGContextSaveGState(mCg);
UnboundnessFixer fixer;
CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp);
CGContextSetAlpha(mCg, aDrawOptions.mAlpha);
CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp));
CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform));
// we don't need to set all of the stroke state because
// it doesn't apply when stroking rects
switch (aStrokeOptions.mLineJoin)
{
case JOIN_BEVEL:
CGContextSetLineJoin(cg, kCGLineJoinBevel);
break;
case JOIN_ROUND:
CGContextSetLineJoin(cg, kCGLineJoinRound);
break;
case JOIN_MITER:
case JOIN_MITER_OR_BEVEL:
CGContextSetLineJoin(cg, kCGLineJoinMiter);
break;
}
CGContextSetLineWidth(cg, aStrokeOptions.mLineWidth);
if (isGradient(aPattern)) {
// There's no CGContextClipStrokeRect so we do it by hand
CGContextBeginPath(cg);
CGContextAddRect(cg, RectToCGRect(aRect));
CGContextReplacePathWithStrokedPath(cg);
//XXX: should we use EO clip here?
CGContextClip(cg);
DrawGradient(cg, aPattern);
} else {
SetStrokeFromPattern(cg, mColorSpace, aPattern);
CGContextStrokeRect(cg, RectToCGRect(aRect));
}
fixer.Fix(mCg);
CGContextRestoreGState(mCg);
}
void
DrawTargetCG::ClearRect(const Rect &aRect)
{
CGContextSaveGState(mCg);
CGContextConcatCTM(mCg, GfxMatrixToCGAffineTransform(mTransform));
CGContextClearRect(mCg, RectToCGRect(aRect));
CGContextRestoreGState(mCg);
}
void
DrawTargetCG::Stroke(const Path *aPath, const Pattern &aPattern, const StrokeOptions &aStrokeOptions, const DrawOptions &aDrawOptions)
{
CGContextSaveGState(mCg);
UnboundnessFixer fixer;
CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp);
CGContextSetAlpha(mCg, aDrawOptions.mAlpha);
CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp));
CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform));
CGContextBeginPath(cg);
assert(aPath->GetBackendType() == BACKEND_COREGRAPHICS);
const PathCG *cgPath = static_cast<const PathCG*>(aPath);
CGContextAddPath(cg, cgPath->GetPath());
SetStrokeOptions(cg, aStrokeOptions);
if (isGradient(aPattern)) {
CGContextReplacePathWithStrokedPath(cg);
//XXX: should we use EO clip here?
CGContextClip(cg);
DrawGradient(cg, aPattern);
} else {
CGContextBeginPath(cg);
// XXX: we could put fill mode into the path fill rule if we wanted
const PathCG *cgPath = static_cast<const PathCG*>(aPath);
CGContextAddPath(cg, cgPath->GetPath());
SetStrokeFromPattern(cg, mColorSpace, aPattern);
CGContextStrokePath(cg);
}
fixer.Fix(mCg);
CGContextRestoreGState(mCg);
}
void
DrawTargetCG::Fill(const Path *aPath, const Pattern &aPattern, const DrawOptions &aDrawOptions)
{
assert(aPath->GetBackendType() == BACKEND_COREGRAPHICS);
CGContextSaveGState(mCg);
CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp));
UnboundnessFixer fixer;
CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp);
CGContextSetAlpha(cg, aDrawOptions.mAlpha);
CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform));
if (isGradient(aPattern)) {
// XXX: we should be able to avoid the extra SaveState that PushClip does
PushClip(aPath);
DrawGradient(cg, aPattern);
PopClip();
} else {
CGContextBeginPath(cg);
// XXX: we could put fill mode into the path fill rule if we wanted
const PathCG *cgPath = static_cast<const PathCG*>(aPath);
CGContextAddPath(cg, cgPath->GetPath());
SetFillFromPattern(cg, mColorSpace, aPattern);
if (cgPath->GetFillRule() == FILL_EVEN_ODD)
CGContextEOFillPath(cg);
else
CGContextFillPath(cg);
}
fixer.Fix(mCg);
CGContextRestoreGState(mCg);
}
void
DrawTargetCG::FillGlyphs(ScaledFont *aFont, const GlyphBuffer &aBuffer, const Pattern &aPattern, const DrawOptions &aDrawOptions)
{
assert(aBuffer.mNumGlyphs);
CGContextSaveGState(mCg);
CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp));
UnboundnessFixer fixer;
CGContextRef cg = fixer.Check(mCg, aDrawOptions.mCompositionOp);
CGContextSetAlpha(cg, aDrawOptions.mAlpha);
CGContextConcatCTM(cg, GfxMatrixToCGAffineTransform(mTransform));
ScaledFontMac* cgFont = static_cast<ScaledFontMac*>(aFont);
CGContextSetFont(cg, cgFont->mFont);
CGContextSetFontSize(cg, cgFont->mSize);
//XXX: we should use a stack vector here when we have a class like that
std::vector<CGGlyph> glyphs;
std::vector<CGPoint> positions;
glyphs.resize(aBuffer.mNumGlyphs);
positions.resize(aBuffer.mNumGlyphs);
CGFloat xprev = aBuffer.mGlyphs[0].mPosition.x;
CGFloat yprev = aBuffer.mGlyphs[0].mPosition.y;
CGContextSetTextPosition(cg, xprev, yprev);
// Handle the flip
CGAffineTransform matrix = CGAffineTransformMakeScale(1, -1);//CGAffineTransformMake(1, 0, 0, -1, 0, -mSize.height);
// "Note that the text matrix is not a part of the graphics state"
CGContextSetTextMatrix(cg, matrix);
for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) {
glyphs[i] = aBuffer.mGlyphs[i].mIndex;
// XXX: CGPointMake might not be inlined
positions[i] = CGPointMake(aBuffer.mGlyphs[i].mPosition.x,
-aBuffer.mGlyphs[i].mPosition.y);
}
//XXX: CGContextShowGlyphsAtPositions is 10.5+ for older versions use CGContextShowGlyphsWithAdvances
if (isGradient(aPattern)) {
CGContextSetTextDrawingMode(cg, kCGTextClip);
CGContextShowGlyphsAtPositions(cg, &glyphs.front(), &positions.front(), aBuffer.mNumGlyphs);
DrawGradient(cg, aPattern);
} else {
//XXX: with CoreGraphics we can stroke text directly instead of going
// through GetPath. It would be nice to add support for using that
CGContextSetTextDrawingMode(cg, kCGTextFill);
SetFillFromPattern(cg, mColorSpace, aPattern);
CGContextShowGlyphsAtPositions(cg, &glyphs.front(), &positions.front(), aBuffer.mNumGlyphs);
}
fixer.Fix(mCg);
CGContextRestoreGState(cg);
}
extern "C" {
void
CGContextResetClip(CGContextRef);
};
void
DrawTargetCG::CopySurface(SourceSurface *aSurface,
const IntRect& aSourceRect,
const IntPoint &aDestination)
{
CGImageRef image;
CGImageRef subimage = NULL;
if (aSurface->GetType() == SURFACE_COREGRAPHICS_IMAGE) {
image = static_cast<SourceSurfaceCG*>(aSurface)->GetImage();
/* we have two options here:
* - create a subimage -- this is slower
* - fancy things with clip and different dest rects */
{
subimage = CGImageCreateWithImageInRect(image, IntRectToCGRect(aSourceRect));
image = subimage;
}
// XXX: it might be more efficient for us to do the copy directly if we have access to the bits
CGContextSaveGState(mCg);
// CopySurface ignores the clip, so we need to use private API to temporarily reset it
CGContextResetClip(mCg);
CGContextSetBlendMode(mCg, kCGBlendModeCopy);
CGContextScaleCTM(mCg, 1, -1);
CGRect flippedRect = CGRectMake(aDestination.x, -(aDestination.y + aSourceRect.height),
aSourceRect.width, aSourceRect.height);
CGContextDrawImage(mCg, flippedRect, image);
CGContextRestoreGState(mCg);
CGImageRelease(subimage);
}
}
void
DrawTargetCG::DrawSurfaceWithShadow(SourceSurface *aSurface, const Point &aDest, const Color &aColor, const Point &aOffset, Float aSigma, CompositionOp aOperator)
{
CGImageRef image;
CGImageRef subimage = NULL;
if (aSurface->GetType() == SURFACE_COREGRAPHICS_IMAGE) {
image = static_cast<SourceSurfaceCG*>(aSurface)->GetImage();
IntSize size = aSurface->GetSize();
CGContextSaveGState(mCg);
//XXX do we need to do the fixup here?
CGContextSetBlendMode(mCg, ToBlendMode(aOperator));
CGContextScaleCTM(mCg, 1, -1);
CGRect flippedRect = CGRectMake(aDest.x, -(aDest.y + size.height),
size.width, size.height);
CGColorRef color = ColorToCGColor(mColorSpace, aColor);
CGSize offset = {aOffset.x, -aOffset.y};
// CoreGraphics needs twice sigma as it's amount of blur
CGContextSetShadowWithColor(mCg, offset, 2*aSigma, color);
CGColorRelease(color);
CGContextDrawImage(mCg, flippedRect, image);
CGContextRestoreGState(mCg);
CGImageRelease(subimage);
}
}
bool
DrawTargetCG::Init(CGContextRef cgContext, const IntSize &aSize)
DrawTargetCG::Init(const IntSize &aSize)
{
// XXX: we should come up with some consistent semantics for dealing
// with zero area drawtargets
if (aSize.width == 0 || aSize.height == 0) {
mColorSpace = NULL;
mCg = NULL;
return false;
}
//XXX: handle SurfaceFormat
//XXX: we'd be better off reusing the Colorspace across draw targets
mColorSpace = CGColorSpaceCreateDeviceRGB();
mSize = aSize;
mCg = cgContext;
mData = NULL;
assert(mCg);
// CGContext's default to have the origin at the bottom left
// so flip it to the top left
CGContextTranslateCTM(mCg, 0, mSize.height);
CGContextScaleCTM(mCg, 1, -1);
//XXX: set correct format
mFormat = FORMAT_B8G8R8A8;
return true;
}
bool
DrawTargetCG::Init(const IntSize &aSize, SurfaceFormat &)
{
// XXX: we should come up with some consistent semantics for dealing
// with zero area drawtargets
if (aSize.width == 0 || aSize.height == 0) {
mColorSpace = NULL;
mCg = NULL;
return false;
}
//XXX: handle SurfaceFormat
//XXX: we'd be better off reusing the Colorspace across draw targets
mColorSpace = CGColorSpaceCreateDeviceRGB();
CGColorSpaceRef cgColorspace;
cgColorspace = CGColorSpaceCreateDeviceRGB();
mSize = aSize;
int bitsPerComponent = 8;
int stride = mSize.width*4;
int stride = mSize.width;
CGBitmapInfo bitinfo;
bitinfo = kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst;
// XXX: currently we allocate ourselves so that we can easily return a gfxImageSurface
// we might not need to later if once we don't need to support gfxImageSurface
//XXX: currently Init implicitly clears, that can often be a waste of time
// XXX: leaked
mData = calloc(mSize.height * stride, 1);
// XXX: what should we do if this fails?
mCg = CGBitmapContextCreate (mData,
mSize.width,
mSize.height,
bitsPerComponent,
stride,
mColorSpace,
bitinfo);
// XXX: mWidth is ugly
mCg = CGBitmapContextCreate (NULL,
mSize.width,
mSize.height,
bitsPerComponent,
stride,
cgColorspace,
bitinfo);
assert(mCg);
// CGContext's default to have the origin at the bottom left
// so flip it to the top left
CGContextTranslateCTM(mCg, 0, mSize.height);
CGContextScaleCTM(mCg, 1, -1);
//XXX: set correct format
mFormat = FORMAT_B8G8R8A8;
CGColorSpaceRelease (cgColorspace);
return true;
}
TemporaryRef<PathBuilder>
DrawTargetCG::CreatePathBuilder(FillRule aFillRule) const
{
RefPtr<PathBuilderCG> pb = new PathBuilderCG(aFillRule);
return pb;
}
void*
DrawTargetCG::GetNativeSurface(NativeSurfaceType aType)
{
if (aType == NATIVE_SURFACE_CGCONTEXT) {
return mCg;
} else {
return NULL;
}
}
void
DrawTargetCG::Mask(const Pattern &aSource,
const Pattern &aMask,
const DrawOptions &aDrawOptions)
{
CGContextSaveGState(mCg);
if (isGradient(aMask)) {
assert(0);
} else {
if (aMask.GetType() == PATTERN_COLOR) {
DrawOptions drawOptions(aDrawOptions);
const Color& color = static_cast<const ColorPattern&>(aMask).mColor;
drawOptions.mAlpha *= color.a;
assert(0);
// XXX: we need to get a rect that when transformed covers the entire surface
//Rect
//FillRect(rect, aSource, drawOptions);
} else if (aMask.GetType() == PATTERN_SURFACE) {
const SurfacePattern& pat = static_cast<const SurfacePattern&>(aMask);
CGImageRef mask = static_cast<SourceSurfaceCG*>(pat.mSurface.get())->GetImage();
Rect rect(0,0, CGImageGetWidth(mask), CGImageGetHeight(mask));
// XXX: probably we need to do some flipping of the image or something
CGContextClipToMask(mCg, RectToCGRect(rect), mask);
FillRect(rect, aSource, aDrawOptions);
}
}
CGContextRestoreGState(mCg);
}
void
DrawTargetCG::PushClipRect(const Rect &aRect)
{
CGContextSaveGState(mCg);
CGContextClipToRect(mCg, RectToCGRect(aRect));
}
void
DrawTargetCG::PushClip(const Path *aPath)
{
CGContextSaveGState(mCg);
CGContextBeginPath(mCg);
assert(aPath->GetBackendType() == BACKEND_COREGRAPHICS);
const PathCG *cgPath = static_cast<const PathCG*>(aPath);
// Weirdly, CoreGraphics clips empty paths as all shown
// but emtpy rects as all clipped. We detect this situation and
// workaround it appropriately
if (CGPathIsEmpty(cgPath->GetPath())) {
// XXX: should we return here?
CGContextClipToRect(mCg, CGRectZero);
}
CGContextAddPath(mCg, cgPath->GetPath());
if (cgPath->GetFillRule() == FILL_EVEN_ODD)
CGContextEOClip(mCg);
else
CGContextClip(mCg);
}
void
DrawTargetCG::PopClip()
{
CGContextRestoreGState(mCg);
}
}
}

View File

@ -35,155 +35,50 @@
*
* ***** END LICENSE BLOCK ***** */
#pragma once
#include <ApplicationServices/ApplicationServices.h>
#include "2D.h"
#include "Rect.h"
#include "PathCG.h"
namespace mozilla {
namespace gfx {
static inline CGAffineTransform
GfxMatrixToCGAffineTransform(Matrix m)
{
CGAffineTransform t;
t.a = m._11;
t.b = m._12;
t.c = m._21;
t.d = m._22;
t.tx = m._31;
t.ty = m._32;
return t;
}
static inline Rect
CGRectToRect(CGRect rect)
{
return Rect(rect.origin.x,
rect.origin.y,
rect.size.width,
rect.size.height);
}
static inline void
SetStrokeOptions(CGContextRef cg, const StrokeOptions &aStrokeOptions)
{
switch (aStrokeOptions.mLineCap)
{
case CAP_BUTT:
CGContextSetLineCap(cg, kCGLineCapButt);
break;
case CAP_ROUND:
CGContextSetLineCap(cg, kCGLineCapRound);
break;
case CAP_SQUARE:
CGContextSetLineCap(cg, kCGLineCapSquare);
break;
}
switch (aStrokeOptions.mLineJoin)
{
case JOIN_BEVEL:
CGContextSetLineJoin(cg, kCGLineJoinBevel);
break;
case JOIN_ROUND:
CGContextSetLineJoin(cg, kCGLineJoinRound);
break;
case JOIN_MITER:
case JOIN_MITER_OR_BEVEL:
CGContextSetLineJoin(cg, kCGLineJoinMiter);
break;
}
CGContextSetLineWidth(cg, aStrokeOptions.mLineWidth);
CGContextSetMiterLimit(cg, aStrokeOptions.mMiterLimit);
// XXX: rename mDashLength to dashLength
if (aStrokeOptions.mDashLength > 1) {
// we use a regular array instead of a std::vector here because we don't want to leak the <vector> include
CGFloat *dashes = new CGFloat[aStrokeOptions.mDashLength];
for (size_t i=0; i<aStrokeOptions.mDashLength; i++) {
dashes[i] = aStrokeOptions.mDashPattern[i];
}
CGContextSetLineDash(cg, aStrokeOptions.mDashOffset, dashes, aStrokeOptions.mDashLength);
delete[] dashes;
}
}
class DrawTargetCG : public DrawTarget
{
public:
DrawTargetCG();
virtual ~DrawTargetCG();
virtual BackendType GetType() const { return BACKEND_COREGRAPHICS; }
virtual BackendType GetType() const { return COREGRAPHICS; }
virtual TemporaryRef<SourceSurface> Snapshot();
virtual void DrawSurface(SourceSurface *aSurface,
const Rect &aDest,
const Rect &aSource,
const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(),
const DrawOptions &aOptions = DrawOptions());
const DrawOptions &aOptions = DrawOptions(),
const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions());
virtual void FillRect(const Rect &aRect,
const Pattern &aPattern,
const DrawOptions &aOptions = DrawOptions());
//XXX: why do we take a reference to SurfaceFormat?
bool Init(const IntSize &aSize, SurfaceFormat&);
bool Init(const IntSize &aSize);
bool Init(CGContextRef cgContext, const IntSize &aSize);
virtual void Flush() {}
virtual void DrawSurfaceWithShadow(SourceSurface *, const Point &, const Color &, const Point &, Float, CompositionOp);
virtual void ClearRect(const Rect &);
virtual void CopySurface(SourceSurface *, const IntRect&, const IntPoint&);
virtual void StrokeRect(const Rect &, const Pattern &, const StrokeOptions&, const DrawOptions&);
virtual void StrokeLine(const Point &, const Point &, const Pattern &, const StrokeOptions &, const DrawOptions &);
virtual void Stroke(const Path *, const Pattern &, const StrokeOptions &, const DrawOptions &);
virtual void Fill(const Path *, const Pattern &, const DrawOptions &);
virtual void FillGlyphs(ScaledFont *, const GlyphBuffer&, const Pattern &, const DrawOptions &);
virtual void Mask(const Pattern &aSource,
const Pattern &aMask,
const DrawOptions &aOptions = DrawOptions());
virtual void PushClip(const Path *);
virtual void PushClipRect(const Rect &aRect);
virtual void PopClip();
virtual TemporaryRef<SourceSurface> CreateSourceSurfaceFromNativeSurface(const NativeSurface&) const { return NULL;}
virtual TemporaryRef<DrawTarget> CreateSimilarDrawTarget(const IntSize &, SurfaceFormat) const;
virtual TemporaryRef<PathBuilder> CreatePathBuilder(FillRule) const;
virtual TemporaryRef<GradientStops> CreateGradientStops(GradientStop *, uint32_t,
ExtendMode aExtendMode = EXTEND_CLAMP) const;
virtual void *GetNativeSurface(NativeSurfaceType);
virtual IntSize GetSize() { return mSize; }
/* This is for creating good compatible surfaces */
virtual TemporaryRef<SourceSurface> CreateSourceSurfaceFromData(unsigned char *aData,
const IntSize &aSize,
int32_t aStride,
SurfaceFormat aFormat) const;
virtual TemporaryRef<SourceSurface> OptimizeSourceSurface(SourceSurface *aSurface) const;
CGContextRef GetCGContext() {
return mCg;
}
private:
bool InitCGRenderTarget();
IntSize mSize;
CGColorSpaceRef mColorSpace;
CGContextRef mCg;
void *mData;
SurfaceFormat mFormat;
};
}

View File

@ -37,7 +37,7 @@
#include "DrawTargetSkia.h"
#include "SourceSurfaceSkia.h"
#include "ScaledFontBase.h"
#include "ScaledFontSkia.h"
#include "skia/SkDevice.h"
#include "skia/SkTypeface.h"
#include "skia/SkGradientShader.h"
@ -58,7 +58,6 @@ namespace gfx {
SkColor ColorToSkColor(const Color &color, Float aAlpha)
{
//XXX: do a better job converting to int
return SkColorSetARGB(color.a*aAlpha*255.0, color.r*255.0, color.g*255.0, color.b*255.0);
}
@ -521,10 +520,10 @@ DrawTargetSkia::FillGlyphs(ScaledFont *aFont,
MarkChanged();
ScaledFontBase* skiaFont = static_cast<ScaledFontBase*>(aFont);
ScaledFontSkia* skiaFont = static_cast<ScaledFontSkia*>(aFont);
AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern);
paint.mPaint.setTypeface(skiaFont->GetSkTypeface());
paint.mPaint.setTypeface(skiaFont->mTypeface);
paint.mPaint.setTextSize(SkFloatToScalar(skiaFont->mSize));
paint.mPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);

View File

@ -44,20 +44,13 @@
#ifdef USE_SKIA
#include "DrawTargetSkia.h"
#include "ScaledFontBase.h"
#endif
#ifdef WIN32
#include "ScaledFontWin.h"
#endif
#ifdef XP_MACOSX
#include "ScaledFontMac.h"
#endif
#ifdef XP_MACOSX
#include "DrawTargetCG.h"
#ifdef WIN32
#include "ScaledFontWin.h"
#endif
#include "ScaledFontSkia.h"
#endif
#ifdef WIN32
@ -97,7 +90,7 @@ Factory::CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFor
}
break;
}
#elif defined XP_MACOSX || defined ANDROID
#endif
#ifdef USE_SKIA
case BACKEND_SKIA:
{
@ -108,18 +101,6 @@ Factory::CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFor
}
break;
}
#endif
#ifdef XP_MACOSX
case BACKEND_COREGRAPHICS:
{
RefPtr<DrawTargetCG> newTarget;
newTarget = new DrawTargetCG();
if (newTarget->Init(aSize, aFormat)) {
return newTarget;
}
break;
}
#endif
#endif
default:
gfxDebug() << "Invalid draw target type specified.";
@ -141,13 +122,13 @@ Factory::CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSiz
return new ScaledFontDWrite(static_cast<IDWriteFontFace*>(aNativeFont.mFont), aSize);
}
#endif
#ifdef USE_SKIA
#ifdef XP_MACOSX
case NATIVE_FONT_MAC_FONT_FACE:
{
return new ScaledFontMac(static_cast<CGFontRef>(aNativeFont.mFont), aSize);
}
#endif
#ifdef USE_SKIA
#ifdef WIN32
case NATIVE_FONT_GDI_FONT_FACE:
{
@ -156,7 +137,7 @@ Factory::CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSiz
#endif
case NATIVE_FONT_SKIA_FONT_FACE:
{
return new ScaledFontBase(static_cast<gfxFont*>(aNativeFont.mFont), aSize);
return new ScaledFontSkia(static_cast<gfxFont*>(aNativeFont.mFont), aSize);
}
#endif
case NATIVE_FONT_CAIRO_FONT_FACE:

View File

@ -62,7 +62,6 @@ EXPORTS_mozilla/gfx = \
Matrix.h \
Rect.h \
Types.h \
UserData.h \
$(NULL)
CPPSRCS = \
@ -73,16 +72,8 @@ CPPSRCS = \
SourceSurfaceCairo.cpp \
PathCairo.cpp \
Blur.cpp \
ScaledFontBase.cpp \
$(NULL)
ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
CPPSRCS += \
SourceSurfaceCG.cpp \
DrawTargetCG.cpp \
PathCG.cpp \
$(NULL)
endif
DEFINES += -DMOZ_GFX -DUSE_CAIRO
@ -91,6 +82,7 @@ CPPSRCS += \
SourceSurfaceSkia.cpp \
DrawTargetSkia.cpp \
PathSkia.cpp \
ScaledFontSkia.cpp \
$(NULL)
DEFINES += -DUSE_SKIA

View File

@ -1,273 +0,0 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Corporation code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bas Schouten <bschouten@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "PathCG.h"
#include <math.h>
#include "DrawTargetCG.h"
#include "Logging.h"
namespace mozilla {
namespace gfx {
PathBuilderCG::~PathBuilderCG()
{
CGPathRelease(mCGPath);
}
void
PathBuilderCG::MoveTo(const Point &aPoint)
{
CGPathMoveToPoint(mCGPath, NULL, aPoint.x, aPoint.y);
}
void
PathBuilderCG::LineTo(const Point &aPoint)
{
if (CGPathIsEmpty(mCGPath))
MoveTo(aPoint);
else
CGPathAddLineToPoint(mCGPath, NULL, aPoint.x, aPoint.y);
}
void
PathBuilderCG::BezierTo(const Point &aCP1,
const Point &aCP2,
const Point &aCP3)
{
if (CGPathIsEmpty(mCGPath))
MoveTo(aCP1);
else
CGPathAddCurveToPoint(mCGPath, NULL,
aCP1.x, aCP1.y,
aCP2.x, aCP2.y,
aCP3.x, aCP3.y);
}
void
PathBuilderCG::QuadraticBezierTo(const Point &aCP1,
const Point &aCP2)
{
if (CGPathIsEmpty(mCGPath))
MoveTo(aCP1);
else
CGPathAddQuadCurveToPoint(mCGPath, NULL,
aCP1.x, aCP1.y,
aCP2.x, aCP2.y);
}
void
PathBuilderCG::Close()
{
if (!CGPathIsEmpty(mCGPath))
CGPathCloseSubpath(mCGPath);
}
void
PathBuilderCG::Arc(const Point &aOrigin, Float aRadius, Float aStartAngle,
Float aEndAngle, bool aAntiClockwise)
{
}
Point
PathBuilderCG::CurrentPoint() const
{
CGPoint pt = CGPathGetCurrentPoint(mCGPath);
Point ret(pt.x, pt.y);
return ret;
}
void
PathBuilderCG::EnsureActive(const Point &aPoint)
{
}
TemporaryRef<Path>
PathBuilderCG::Finish()
{
RefPtr<PathCG> path = new PathCG(mCGPath, mFillRule);
return path;
}
TemporaryRef<PathBuilder>
PathCG::CopyToBuilder(FillRule aFillRule) const
{
CGMutablePathRef path = CGPathCreateMutableCopy(mPath);
RefPtr<PathBuilderCG> builder = new PathBuilderCG(path, aFillRule);
return builder;
}
TemporaryRef<PathBuilder>
PathCG::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) const
{
// 10.7 adds CGPathCreateMutableCopyByTransformingPath it might be faster than doing
// this by hand
struct TransformApplier {
CGMutablePathRef path;
CGAffineTransform transform;
static void
TranformCGPathApplierFunc(void *vinfo, const CGPathElement *element)
{
TransformApplier *info = reinterpret_cast<TransformApplier*>(vinfo);
switch (element->type) {
case kCGPathElementMoveToPoint:
{
CGPoint pt = element->points[0];
CGPathMoveToPoint(info->path, &info->transform, pt.x, pt.y);
break;
}
case kCGPathElementAddLineToPoint:
{
CGPoint pt = element->points[0];
CGPathAddLineToPoint(info->path, &info->transform, pt.x, pt.y);
break;
}
case kCGPathElementAddQuadCurveToPoint:
{
CGPoint pt = element->points[0];
CGPoint cpt = element->points[1];
CGPathAddQuadCurveToPoint(info->path, &info->transform, cpt.x, cpt.y, pt.x, pt.y);
break;
}
case kCGPathElementAddCurveToPoint:
{
CGPoint pt = element->points[0];
CGPoint cpt1 = element->points[1];
CGPoint cpt2 = element->points[2];
CGPathAddCurveToPoint(info->path, &info->transform, cpt1.x, cpt1.y, cpt2.x, cpt2.y, pt.x, pt.y);
break;
}
case kCGPathElementCloseSubpath:
{
CGPathCloseSubpath(info->path);
break;
}
}
}
};
TransformApplier ta;
ta.path = CGPathCreateMutable();
ta.transform = GfxMatrixToCGAffineTransform(aTransform);
CGPathApply(mPath, &ta, TransformApplier::TranformCGPathApplierFunc);
RefPtr<PathBuilderCG> builder = new PathBuilderCG(ta.path, aFillRule);
return builder;
}
bool
PathCG::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const
{
Matrix inverse = aTransform;
inverse.Invert();
Point transformedPoint = inverse*aPoint;
// We could probably drop the input transform and just transform the point at the caller?
CGPoint point = {transformedPoint.x, transformedPoint.y};
// The transform parameter of CGPathContainsPoint doesn't seem to work properly on OS X 10.5
// so we transform aPoint ourselves.
return CGPathContainsPoint(mPath, NULL, point, mFillRule == FILL_EVEN_ODD);
}
static size_t
PutBytesNull(void *info, const void *buffer, size_t count)
{
return count;
}
/* The idea of a scratch context comes from WebKit */
static CGContextRef
CreateScratchContext()
{
CGDataConsumerCallbacks callbacks = {PutBytesNull, NULL};
CGDataConsumerRef consumer = CGDataConsumerCreate(NULL, &callbacks);
CGContextRef cg = CGPDFContextCreate(consumer, NULL, NULL);
CGDataConsumerRelease(consumer);
return cg;
}
static CGContextRef
ScratchContext()
{
static CGContextRef cg = CreateScratchContext();
return cg;
}
//XXX: what should these functions return for an empty path?
// currently they return CGRectNull {inf,inf, 0, 0}
Rect
PathCG::GetBounds(const Matrix &aTransform) const
{
//XXX: are these bounds tight enough
Rect bounds = CGRectToRect(CGPathGetBoundingBox(mPath));
//XXX: curretnly this returns the bounds of the transformed bounds
// this is strictly looser than the bounds of the transformed path
return aTransform.TransformBounds(bounds);
}
Rect
PathCG::GetStrokedBounds(const StrokeOptions &aStrokeOptions,
const Matrix &aTransform) const
{
// 10.7 has CGPathCreateCopyByStrokingPath which we could use
// instead of this scratch context business
CGContextRef cg = ScratchContext();
CGContextSaveGState(cg);
CGContextBeginPath(cg);
CGContextAddPath(cg, mPath);
SetStrokeOptions(cg, aStrokeOptions);
CGContextReplacePathWithStrokedPath(cg);
Rect bounds = CGRectToRect(CGContextGetPathBoundingBox(cg));
CGContextRestoreGState(cg);
return aTransform.TransformBounds(bounds);
}
}
}

View File

@ -1,133 +0,0 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Corporation code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bas Schouten <bschouten@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef MOZILLA_GFX_PATHCG_H_
#define MOZILLA_GFX_PATHCG_H_
#include <ApplicationServices/ApplicationServices.h>
#include "2D.h"
namespace mozilla {
namespace gfx {
class PathCG;
class PathBuilderCG : public PathBuilder
{
public:
// absorbs a reference of aPath
PathBuilderCG(CGMutablePathRef aPath, FillRule aFillRule)
: mFigureActive(false)
, mFillRule(aFillRule)
{
mCGPath = aPath;
}
PathBuilderCG(FillRule aFillRule)
: mFigureActive(false)
, mFillRule(aFillRule)
{
mCGPath = CGPathCreateMutable();
}
virtual ~PathBuilderCG();
virtual void MoveTo(const Point &aPoint);
virtual void LineTo(const Point &aPoint);
virtual void BezierTo(const Point &aCP1,
const Point &aCP2,
const Point &aCP3);
virtual void QuadraticBezierTo(const Point &aCP1,
const Point &aCP2);
virtual void Close();
virtual void Arc(const Point &aOrigin, Float aRadius, Float aStartAngle,
Float aEndAngle, bool aAntiClockwise = false);
virtual Point CurrentPoint() const;
virtual TemporaryRef<Path> Finish();
private:
friend class PathCG;
void EnsureActive(const Point &aPoint);
CGMutablePathRef mCGPath;
bool mFigureActive;
Point mCurrentPoint;
Point mBeginPoint;
FillRule mFillRule;
};
class PathCG : public Path
{
public:
PathCG(CGMutablePathRef aPath, FillRule aFillRule)
: mPath(aPath)
, mFillRule(aFillRule)
{
CGPathRetain(mPath);
}
virtual ~PathCG() { CGPathRelease(mPath); }
virtual BackendType GetBackendType() const { return BACKEND_COREGRAPHICS; }
virtual TemporaryRef<PathBuilder> CopyToBuilder(FillRule aFillRule = FILL_WINDING) const;
virtual TemporaryRef<PathBuilder> TransformedCopyToBuilder(const Matrix &aTransform,
FillRule aFillRule = FILL_WINDING) const;
virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const;
virtual Rect GetBounds(const Matrix &aTransform = Matrix()) const;
virtual Rect GetStrokedBounds(const StrokeOptions &aStrokeOptions,
const Matrix &aTransform = Matrix()) const;
virtual FillRule GetFillRule() const { return mFillRule; }
CGMutablePathRef GetPath() const { return mPath; }
private:
friend class DrawTargetCG;
CGMutablePathRef mPath;
bool mEndedActive;
Point mEndPoint;
FillRule mFillRule;
};
}
}
#endif

View File

@ -36,76 +36,25 @@
* ***** END LICENSE BLOCK ***** */
#include "ScaledFontMac.h"
#ifdef USE_SKIA
#include "PathSkia.h"
#include "skia/SkPaint.h"
#include "skia/SkPath.h"
#include "skia/SkTypeface_mac.h"
#endif
#include "DrawTargetCG.h"
#include <vector>
// prototype for private API
extern "C" {
CGPathRef CGFontGetGlyphPath(CGFontRef fontRef, CGAffineTransform *textTransform, int unknown, CGGlyph glyph);
};
namespace mozilla {
namespace gfx {
ScaledFontMac::ScaledFontMac(CGFontRef aFont, Float aSize)
: ScaledFontBase(aSize)
: ScaledFontSkia(aSize)
{
// XXX: should we be taking a reference
mFont = CGFontRetain(aFont);
mFontFace = CTFontCreateWithGraphicsFont(aFont, aSize, NULL, NULL);
mTypeface = SkCreateTypefaceFromCTFont(mFontFace);
}
ScaledFontMac::~ScaledFontMac()
{
CGFontRelease(mFont);
}
#ifdef USE_SKIA
SkTypeface* ScaledFontMac::GetSkTypeface()
{
if (!mTypeface) {
CTFontRef fontFace = CTFontCreateWithGraphicsFont(mFont, mSize, NULL, NULL);
mTypeface = SkCreateTypefaceFromCTFont(fontFace);
CFRelease(fontFace);
}
return mTypeface;
}
#endif
// private API here are the public options on OS X
// CTFontCreatePathForGlyph
// ATSUGlyphGetCubicPaths
// we've used this in cairo sucessfully for some time.
// Note: cairo dlsyms it. We could do that but maybe it's
// safe just to use?
TemporaryRef<Path>
ScaledFontMac::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget)
{
if (aTarget->GetType() == BACKEND_COREGRAPHICS) {
CGMutablePathRef path = CGPathCreateMutable();
for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) {
// XXX: we could probably fold both of these transforms together to avoid extra work
CGAffineTransform flip = CGAffineTransformMakeScale(1, -1);
CGPathRef glyphPath = ::CGFontGetGlyphPath(mFont, &flip, 0, aBuffer.mGlyphs[i].mIndex);
CGAffineTransform matrix = CGAffineTransformMake(mSize, 0, 0, mSize,
aBuffer.mGlyphs[i].mPosition.x,
aBuffer.mGlyphs[i].mPosition.y);
CGPathAddPath(path, &matrix, glyphPath);
CGPathRelease(glyphPath);
}
return new PathCG(path, FILL_WINDING);
} else {
return ScaledFontBase::GetPathForGlyphs(aBuffer, aTarget);
}
CFRelease(mFontFace);
}
}

View File

@ -38,28 +38,25 @@
#ifndef MOZILLA_GFX_SCALEDFONTMAC_H_
#define MOZILLA_GFX_SCALEDFONTMAC_H_
#include "ScaledFontSkia.h"
#import <ApplicationServices/ApplicationServices.h>
#include "2D.h"
#include "ScaledFontBase.h"
namespace mozilla {
namespace gfx {
class ScaledFontMac : public ScaledFontBase
class ScaledFontMac : public ScaledFontSkia
{
public:
ScaledFontMac(CGFontRef aFont, Float aSize);
virtual ~ScaledFontMac();
virtual FontType GetType() const { return FONT_MAC; }
#ifdef USE_SKIA
virtual SkTypeface* GetSkTypeface();
#endif
virtual TemporaryRef<Path> GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget);
private:
friend class DrawTargetCG;
CGFontRef mFont;
friend class DrawTargetSkia;
CTFontRef mFontFace;
};
}

72
gfx/2d/ScaledFontBase.cpp → gfx/2d/ScaledFontSkia.cpp Normal file → Executable file
View File

@ -35,12 +35,10 @@
*
* ***** END LICENSE BLOCK ***** */
#include "ScaledFontBase.h"
#ifdef USE_SKIA
#include "ScaledFontSkia.h"
#include "PathSkia.h"
#include "skia/SkPaint.h"
#include "skia/SkPath.h"
#endif
#include <vector>
#include <cmath>
using namespace std;
@ -48,7 +46,7 @@ using namespace std;
namespace mozilla {
namespace gfx {
#ifdef USE_SKIA
static SkTypeface::Style gfxFontStyleToSkia(const gfxFontStyle* aStyle)
{
if (aStyle->style == NS_FONT_STYLE_ITALIC) {
@ -63,57 +61,49 @@ static SkTypeface::Style gfxFontStyleToSkia(const gfxFontStyle* aStyle)
return SkTypeface::kNormal;
}
ScaledFontBase::ScaledFontBase(gfxFont* aFont, Float aSize)
ScaledFontSkia::ScaledFontSkia(gfxFont* aFont, Float aSize)
: mSize(aSize)
{
NS_LossyConvertUTF16toASCII name(aFont->GetName());
mTypeface = SkTypeface::CreateFromName(name.get(), gfxFontStyleToSkia(aFont->GetStyle()));
}
#endif
ScaledFontBase::~ScaledFontBase()
{
#ifdef USE_SKIA
SkSafeUnref(mTypeface);
#endif
}
ScaledFontBase::ScaledFontBase(Float aSize)
ScaledFontSkia::ScaledFontSkia(Float aSize)
: mSize(aSize)
{
#ifdef USE_SKIA
mTypeface = NULL;
#endif
}
ScaledFontSkia::~ScaledFontSkia()
{
SkSafeUnref(mTypeface);
}
TemporaryRef<Path>
ScaledFontBase::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget)
ScaledFontSkia::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget)
{
#ifdef USE_SKIA
if (aTarget->GetType() == BACKEND_SKIA) {
SkPaint paint;
paint.setTypeface(GetSkTypeface());
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
paint.setTextSize(SkFloatToScalar(mSize));
std::vector<uint16_t> indices;
std::vector<SkPoint> offsets;
indices.resize(aBuffer.mNumGlyphs);
offsets.resize(aBuffer.mNumGlyphs);
for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) {
indices[i] = aBuffer.mGlyphs[i].mIndex;
offsets[i].fX = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.x);
offsets[i].fY = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.y);
}
SkPath path;
paint.getPosTextPath(&indices.front(), aBuffer.mNumGlyphs*2, &offsets.front(), &path);
return new PathSkia(path, FILL_WINDING);
if (aTarget->GetType() != BACKEND_SKIA) {
return NULL;
}
#endif
return NULL;
SkPaint paint;
paint.setTypeface(mTypeface);
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
paint.setTextSize(SkFloatToScalar(mSize));
std::vector<uint16_t> indices;
std::vector<SkPoint> offsets;
indices.resize(aBuffer.mNumGlyphs);
offsets.resize(aBuffer.mNumGlyphs);
for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) {
indices[i] = aBuffer.mGlyphs[i].mIndex;
offsets[i].fX = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.x);
offsets[i].fY = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.y);
}
SkPath path;
paint.getPosTextPath(&indices.front(), aBuffer.mNumGlyphs*2, &offsets.front(), &path);
return new PathSkia(path, FILL_WINDING);
}
}

25
gfx/2d/ScaledFontBase.h → gfx/2d/ScaledFontSkia.h Normal file → Executable file
View File

@ -35,41 +35,36 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef MOZILLA_GFX_SCALEDFONTBASE_H_
#define MOZILLA_GFX_SCALEDFONTBASE_H_
#ifndef MOZILLA_GFX_SCALEDFONTSKIA_H_
#define MOZILLA_GFX_SCALEDFONTSKIA_H_
#include "2D.h"
#ifdef USE_SKIA
#include "skia/SkTypeface.h"
#endif
class gfxFont;
namespace mozilla {
namespace gfx {
class ScaledFontBase : public ScaledFont
class ScaledFontSkia : public ScaledFont
{
public:
ScaledFontBase(Float aSize);
virtual ~ScaledFontBase();
ScaledFontSkia(gfxFont* aFont, Float aSize);
ScaledFontSkia(Float aSize);
virtual ~ScaledFontSkia();
virtual FontType GetType() const { return FONT_SKIA; }
virtual TemporaryRef<Path> GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget);
#ifdef USE_SKIA
ScaledFontBase(gfxFont* aFont, Float aSize);
virtual SkTypeface* GetSkTypeface() { return mTypeface; }
virtual FontType GetType() const { return FONT_SKIA; }
#endif
protected:
friend class DrawTargetSkia;
#ifdef USE_SKIA
SkTypeface* mTypeface;
#endif
Float mSize;
};
}
}
#endif /* MOZILLA_GFX_SCALEDFONTBASE_H_ */
#endif /* MOZILLA_GFX_SCALEDFONTSKIA_H_ */

View File

@ -36,32 +36,18 @@
* ***** END LICENSE BLOCK ***** */
#include "ScaledFontWin.h"
#include "ScaeldFontBase.h"
#ifdef USE_SKIA
#include "skia/SkTypeface_win.h"
#endif
namespace mozilla {
namespace gfx {
ScaledFontWin::ScaledFontWin(gfxGDIFont* aFont, Float aSize)
: ScaledFontBase(aSize)
: ScaledFontSkia(aSize)
{
LOGFONT lf;
GetObject(aFont->GetHFONT(), sizeof(LOGFONT), &lf);
mTypeface = SkCreateTypefaceFromLOGFONT(lf);
}
#ifdef USE_SKIA
SkTypeface* ScaledFontWin::GetSkTypeface()
{
if (!mTypeface) {
mTypeface = SkCreateTypefaceFromLOGFONT(lf);
}
return mTypeface;
}
#endif
}
}

View File

@ -38,25 +38,21 @@
#ifndef MOZILLA_GFX_SCALEDFONTWIN_H_
#define MOZILLA_GFX_SCALEDFONTWIN_H_
#include "ScaledFontBase.h"
#include "ScaledFontSkia.h"
#include "gfxGDIFont.h"
namespace mozilla {
namespace gfx {
class ScaledFontWin : public ScaledFontBase
class ScaledFontWin : public ScaledFontSkia
{
public:
ScaledFontWin(gfxGDIFont* aFont, Float aSize);
virtual FontType GetType() const { return FONT_GDI; }
#ifdef USE_SKIA
virtual SkTypeface* GetSkTypeface();
#endif
private:
#ifdef USE_SKIA
friend class DrawTargetSkia;
#endif
};
}

View File

@ -40,6 +40,9 @@
namespace mozilla {
namespace gfx {
SourceSurfaceCG::SourceSurfaceCG()
{
}
SourceSurfaceCG::~SourceSurfaceCG()
{
@ -50,8 +53,8 @@ IntSize
SourceSurfaceCG::GetSize() const
{
IntSize size;
size.width = CGImageGetWidth(mImage);
size.height = CGImageGetHeight(mImage);
size.width = CGImageGetHeight(mImage);
size.height = CGImageGetWidth(mImage);
return size;
}
@ -64,13 +67,10 @@ SourceSurfaceCG::GetFormat() const
TemporaryRef<DataSourceSurface>
SourceSurfaceCG::GetDataSurface()
{
//XXX: we should be more disciplined about who takes a reference and where
CGImageRetain(mImage);
RefPtr<DataSourceSurfaceCG> dataSurf =
new DataSourceSurfaceCG(mImage);
return dataSurf;
return NULL;
}
static void releaseCallback(void *info, const void *data, size_t size) {
free(info);
}
@ -88,24 +88,22 @@ SourceSurfaceCG::InitFromData(unsigned char *aData,
int bitsPerComponent = 0;
int bitsPerPixel = 0;
assert(aSize.width >= 0 && aSize.height >= 0);
switch (aFormat) {
case FORMAT_B8G8R8A8:
case B8G8R8A8:
colorSpace = CGColorSpaceCreateDeviceRGB();
bitinfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
bitsPerComponent = 8;
bitsPerPixel = 32;
break;
case FORMAT_B8G8R8X8:
case B8G8R8X8:
colorSpace = CGColorSpaceCreateDeviceRGB();
bitinfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host;
bitsPerComponent = 8;
bitsPerPixel = 32;
break;
case FORMAT_A8:
case A8:
// XXX: why don't we set a colorspace here?
bitsPerComponent = 8;
bitsPerPixel = 8;
@ -121,7 +119,7 @@ SourceSurfaceCG::InitFromData(unsigned char *aData,
aSize.height * aStride,
releaseCallback);
if (aFormat == FORMAT_A8) {
if (aFormat == A8) {
CGFloat decode[] = {1.0, 0.0};
mImage = CGImageMaskCreate (aSize.width, aSize.height,
bitsPerComponent,
@ -147,173 +145,12 @@ SourceSurfaceCG::InitFromData(unsigned char *aData,
CGDataProviderRelease(dataProvider);
CGColorSpaceRelease (colorSpace);
return mImage != NULL;
}
DataSourceSurfaceCG::~DataSourceSurfaceCG()
{
CGImageRelease(mImage);
free(CGBitmapContextGetData(mCg));
CGContextRelease(mCg);
}
IntSize
DataSourceSurfaceCG::GetSize() const
{
IntSize size;
size.width = CGImageGetWidth(mImage);
size.height = CGImageGetHeight(mImage);
return size;
}
bool
DataSourceSurfaceCG::InitFromData(unsigned char *aData,
const IntSize &aSize,
int32_t aStride,
SurfaceFormat aFormat)
{
//XXX: we should avoid creating this colorspace everytime
CGColorSpaceRef colorSpace = NULL;
CGBitmapInfo bitinfo = 0;
CGDataProviderRef dataProvider = NULL;
int bitsPerComponent = 0;
int bitsPerPixel = 0;
switch (aFormat) {
case FORMAT_B8G8R8A8:
colorSpace = CGColorSpaceCreateDeviceRGB();
bitinfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
bitsPerComponent = 8;
bitsPerPixel = 32;
break;
case FORMAT_B8G8R8X8:
colorSpace = CGColorSpaceCreateDeviceRGB();
bitinfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host;
bitsPerComponent = 8;
bitsPerPixel = 32;
break;
case FORMAT_A8:
// XXX: why don't we set a colorspace here?
bitsPerComponent = 8;
bitsPerPixel = 8;
};
void *data = malloc(aStride * aSize.height);
memcpy(data, aData, aStride * aSize.height);
//mFormat = aFormat;
dataProvider = CGDataProviderCreateWithData (data,
data,
aSize.height * aStride,
releaseCallback);
if (aFormat == FORMAT_A8) {
CGFloat decode[] = {1.0, 0.0};
mImage = CGImageMaskCreate (aSize.width, aSize.height,
bitsPerComponent,
bitsPerPixel,
aStride,
dataProvider,
decode,
true);
} else {
mImage = CGImageCreate (aSize.width, aSize.height,
bitsPerComponent,
bitsPerPixel,
aStride,
colorSpace,
bitinfo,
dataProvider,
NULL,
true,
kCGRenderingIntentDefault);
if (mImage) {
return false;
}
CGDataProviderRelease(dataProvider);
CGColorSpaceRelease (colorSpace);
return mImage;
return true;
}
CGContextRef CreateBitmapContextForImage(CGImageRef image)
{
CGColorSpaceRef colorSpace;
size_t width = CGImageGetWidth(image);
size_t height = CGImageGetHeight(image);
int bitmapBytesPerRow = (width * 4);
int bitmapByteCount = (bitmapBytesPerRow * height);
void *data = calloc(bitmapByteCount, 1);
//XXX: which color space should we be using here?
colorSpace = CGColorSpaceCreateDeviceRGB();
assert(colorSpace);
// we'd like to pass NULL as the first parameter
// to let Quartz manage this memory for us. However,
// on 10.5 and older CGBitmapContextGetData will return
// NULL instead of the associated buffer so we need
// to manage it ourselves.
CGContextRef cg = CGBitmapContextCreate(data,
width,
height,
8,
bitmapBytesPerRow,
colorSpace,
kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst);
assert(cg);
CGColorSpaceRelease(colorSpace);
return cg;
}
DataSourceSurfaceCG::DataSourceSurfaceCG(CGImageRef aImage)
{
mImage = aImage;
mCg = CreateBitmapContextForImage(aImage);
if (mCg == NULL) {
// error creating context
return;
}
// Get image width, height. We'll use the entire image.
CGFloat w = CGImageGetWidth(aImage);
CGFloat h = CGImageGetHeight(aImage);
CGRect rect = {{0,0},{w,h}};
// Draw the image to the bitmap context. Once we draw, the memory
// allocated for the context for rendering will then contain the
// raw image data in the specified color space.
CGContextDrawImage(mCg, rect, aImage);
// Now we can get a pointer to the image data associated with the bitmap
// context.
mData = CGBitmapContextGetData(mCg);
assert(mData);
}
unsigned char *
DataSourceSurfaceCG::GetData()
{
// See http://developer.apple.com/library/mac/#qa/qa1509/_index.html
// the following only works on 10.5+, the Q&A above suggests a method
// that can be used for earlier versions
//CFDataRef data = CGDataProviderCopyData(CGImageGetDataProvider(cgImage));
//unsigned char *dataPtr = CFDataGetBytePtr(data);
//CFDataRelease(data);
// unfortunately the the method above only works for read-only access and
// we need read-write for DataSourceSurfaces
return (unsigned char*)mData;
}
}
}

View File

@ -47,11 +47,10 @@ namespace gfx {
class SourceSurfaceCG : public SourceSurface
{
public:
SourceSurfaceCG() {}
SourceSurfaceCG(CGImageRef aImage) : mImage(aImage) {}
SourceSurfaceCG();
~SourceSurfaceCG();
virtual SurfaceType GetType() const { return SURFACE_COREGRAPHICS_IMAGE; }
virtual SurfaceType GetType() const { return COREGRAPHICS_IMAGE; }
virtual IntSize GetSize() const;
virtual SurfaceFormat GetFormat() const;
virtual TemporaryRef<DataSourceSurface> GetDataSurface();
@ -72,38 +71,5 @@ private:
SurfaceFormat mFormat;
};
class DataSourceSurfaceCG : public DataSourceSurface
{
public:
DataSourceSurfaceCG() {}
DataSourceSurfaceCG(CGImageRef aImage);
~DataSourceSurfaceCG();
virtual SurfaceType GetType() const { return SURFACE_DATA; }
virtual IntSize GetSize() const;
virtual SurfaceFormat GetFormat() const { return FORMAT_B8G8R8A8; }
CGImageRef GetImage() { return mImage; }
bool InitFromData(unsigned char *aData,
const IntSize &aSize,
int32_t aStride,
SurfaceFormat aFormat);
virtual unsigned char *GetData();
virtual int32_t Stride() { return CGImageGetBytesPerRow(mImage); }
private:
CGContextRef mCg;
CGImageRef mImage;
//XXX: we don't need to store mData we can just get it from the CGContext
void *mData;
/* It might be better to just use the bitmap info from the CGImageRef to
* deduce the format to save space in SourceSurfaceCG,
* for now we just store it in mFormat */
};
}
}

View File

@ -80,15 +80,13 @@ enum FontType
FONT_GDI,
FONT_MAC,
FONT_SKIA,
FONT_CAIRO,
FONT_COREGRAPHICS
FONT_CAIRO
};
enum NativeSurfaceType
{
NATIVE_SURFACE_D3D10_TEXTURE,
NATIVE_SURFACE_CAIRO_SURFACE,
NATIVE_SURFACE_CGCONTEXT
NATIVE_SURFACE_CAIRO_SURFACE
};
enum NativeFontType

View File

@ -1,108 +0,0 @@
/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Corporation code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (Sub) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Jeff Muizelaar <jmuizelaar@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <stdlib.h>
#include "mozilla/mozalloc.h"
namespace mozilla {
namespace gfx {
struct UserDataKey {
int unused;
};
/* this class is basically a clone of the user data concept from cairo */
class UserData
{
typedef void (*destroyFunc)(void *data);
public:
UserData() : count(0), entries(NULL) {}
/* Attaches untyped userData associated with key. destroy is called on destruction */
void Add(UserDataKey *key, void *userData, destroyFunc destroy)
{
// We could keep entries in a std::vector instead of managing it by hand
// but that would propagate an stl dependency out which we'd rather not
// do (see bug 666609). Plus, the entries array is expect to stay small
// so doing a realloc everytime we add a new entry shouldn't be too costly
entries = static_cast<Entry*>(moz_xrealloc(entries, sizeof(Entry)*(count+1)));
entries[count].key = key;
entries[count].userData = userData;
entries[count].destroy = destroy;
count++;
}
//XXX: we probably want to add a way to remove Keys
/* Retrives the userData for the associated key */
void *Get(UserDataKey *key)
{
for (int i=0; i<count; i++) {
if (key == entries[i].key) {
return entries[i].userData;
}
}
return NULL;
}
~UserData()
{
for (int i=0; i<count; i++) {
entries[i].destroy(entries[i].userData);
}
free(entries);
}
private:
struct Entry {
const UserDataKey *key;
void *userData;
destroyFunc destroy;
};
int count;
Entry *entries;
};
}
}

View File

@ -683,7 +683,7 @@ struct gfxTextRange {
* completely, with all its words, and avoid the cost of aging the words
* individually. That only happens with longer-lived fonts.
*/
class THEBES_API gfxFontCache MOZ_FINAL : public nsExpirationTracker<gfxFont,3> {
class THEBES_API gfxFontCache : public nsExpirationTracker<gfxFont,3> {
public:
enum {
FONT_TIMEOUT_SECONDS = 10,

View File

@ -532,26 +532,9 @@ DataSourceSurfaceDestroy(void *dataSourceSurface)
static_cast<DataSourceSurface*>(dataSourceSurface)->Release();
}
void DestroyThebesSurface(void *data)
{
gfxASurface *surface = static_cast<gfxASurface*>(data);
surface->Release();
}
UserDataKey ThebesSurfaceKey;
// The semantics of this function are sort of weird. We snapshot the first
// time and then return the snapshotted surface for the lifetime of the
// draw target
already_AddRefed<gfxASurface>
gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
{
void *surface = aTarget->GetUserData(&ThebesSurfaceKey);
if (surface) {
nsRefPtr<gfxASurface> surf = static_cast<gfxASurface*>(surface);
return surf.forget();
}
RefPtr<SourceSurface> source = aTarget->Snapshot();
RefPtr<DataSourceSurface> data = source->GetDataSurface();
@ -562,18 +545,12 @@ gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
IntSize size = data->GetSize();
gfxASurface::gfxImageFormat format = gfxASurface::FormatFromContent(ContentForFormat(data->GetFormat()));
nsRefPtr<gfxImageSurface> surf =
nsRefPtr<gfxImageSurface> image =
new gfxImageSurface(data->GetData(), gfxIntSize(size.width, size.height),
data->Stride(), format);
surf->SetData(&kDrawSourceSurface, data.forget().drop(), DataSourceSurfaceDestroy);
// add a reference to be held by the drawTarget
// careful, the reference graph is getting complicated here
surf->AddRef();
aTarget->AddUserData(&ThebesSurfaceKey, surf.get(), DestroyThebesSurface);
return surf.forget();
image->SetData(&kDrawSourceSurface, data.forget().drop(), DataSourceSurfaceDestroy);
return image.forget();
}
RefPtr<DrawTarget>

View File

@ -71,9 +71,6 @@ class gfxTextRun;
class nsIURI;
class nsIAtom;
extern mozilla::gfx::UserDataKey ThebesSurfaceKey;
void DestroyThebesSurface(void *data);
extern cairo_user_data_key_t kDrawTarget;
// pref lang id's for font prefs

View File

@ -57,7 +57,6 @@
#include "qcms.h"
#include <dlfcn.h>
#include "mozilla/gfx/2D.h"
using namespace mozilla;
using namespace mozilla::gfx;
@ -132,7 +131,7 @@ gfxPlatformMac::CreateOffscreenSurface(const gfxIntSize& size,
NS_IF_ADDREF(newSurface);
return newSurface;
}
already_AddRefed<gfxASurface>
gfxPlatformMac::OptimizeImage(gfxImageSurface *aSurface,
gfxASurface::gfxImageFormat format)
@ -163,7 +162,7 @@ gfxPlatformMac::GetScaledFontForFont(gfxFont *aFont)
bool
gfxPlatformMac::SupportsAzure(BackendType& aBackend)
{
aBackend = BACKEND_COREGRAPHICS;
aBackend = BACKEND_SKIA;
return true;
}
@ -299,36 +298,6 @@ gfxPlatformMac::ReadAntiAliasingThreshold()
return threshold;
}
already_AddRefed<gfxASurface>
gfxPlatformMac::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
{
if (aTarget->GetType() == BACKEND_COREGRAPHICS) {
void *surface = aTarget->GetUserData(&ThebesSurfaceKey);
if (surface) {
nsRefPtr<gfxASurface> surf = static_cast<gfxQuartzSurface*>(surface);
return surf.forget();
} else {
CGContextRef cg = static_cast<CGContextRef>(aTarget->GetNativeSurface(NATIVE_SURFACE_CGCONTEXT));
//XXX: it would be nice to have an implicit conversion from IntSize to gfxIntSize
IntSize intSize = aTarget->GetSize();
gfxIntSize size(intSize.width, intSize.height);
nsRefPtr<gfxASurface> surf =
new gfxQuartzSurface(cg, size);
// add a reference to be held by the drawTarget
surf->AddRef();
aTarget->AddUserData(&ThebesSurfaceKey, surf.get(), DestroyThebesSurface);
return surf.forget();
}
}
return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget);
}
qcms_profile *
gfxPlatformMac::GetPlatformCMSOutputProfile()
{

View File

@ -50,7 +50,6 @@
#define MAC_OS_X_MAJOR_VERSION_MASK 0xFFFFFFF0U
class gfxTextRun;
class mozilla::gfx::DrawTarget;
class THEBES_API gfxPlatformMac : public gfxPlatform {
public:
@ -105,8 +104,6 @@ public:
// lower threshold on font anti-aliasing
PRUint32 GetAntiAliasingThreshold() { return mFontAntiAliasingThreshold; }
virtual already_AddRefed<gfxASurface>
GetThebesSurfaceForDrawTarget(mozilla::gfx::DrawTarget *aTarget);
private:
virtual qcms_profile* GetPlatformCMSOutputProfile();

View File

@ -81,26 +81,6 @@ gfxQuartzSurface::gfxQuartzSurface(CGContextRef context,
unsigned int width = static_cast<unsigned int>(mSize.width);
unsigned int height = static_cast<unsigned int>(mSize.height);
cairo_surface_t *surf =
cairo_quartz_surface_create_for_cg_context(context,
width, height);
CGContextRetain(mCGContext);
Init(surf);
}
gfxQuartzSurface::gfxQuartzSurface(CGContextRef context,
const gfxIntSize& size,
bool aForPrinting)
: mCGContext(context), mSize(size), mForPrinting(aForPrinting)
{
if (!CheckSurfaceSize(size))
MakeInvalid();
unsigned int width = static_cast<unsigned int>(mSize.width);
unsigned int height = static_cast<unsigned int>(mSize.height);
cairo_surface_t *surf =
cairo_quartz_surface_create_for_cg_context(context,
width, height);

View File

@ -50,7 +50,6 @@ class THEBES_API gfxQuartzSurface : public gfxASurface {
public:
gfxQuartzSurface(const gfxSize& size, gfxImageFormat format, bool aForPrinting = false);
gfxQuartzSurface(CGContextRef context, const gfxSize& size, bool aForPrinting = false);
gfxQuartzSurface(CGContextRef context, const gfxIntSize& size, bool aForPrinting = false);
gfxQuartzSurface(cairo_surface_t *csurf, bool aForPrinting = false);
gfxQuartzSurface(unsigned char *data, const gfxSize& size, long stride, gfxImageFormat format, bool aForPrinting = false);

View File

@ -507,35 +507,21 @@ gfxWindowsPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
{
#ifdef XP_WIN
if (aTarget->GetType() == BACKEND_DIRECT2D) {
void *surface = aTarget->GetUserData(&ThebesSurfaceKey);
if (surface) {
nsRefPtr<gfxASurface> surf = static_cast<gfxASurface*>(surface);
return surf.forget();
} else {
RefPtr<ID3D10Texture2D> texture =
static_cast<ID3D10Texture2D*>(aTarget->GetNativeSurface(NATIVE_SURFACE_D3D10_TEXTURE));
RefPtr<ID3D10Texture2D> texture =
static_cast<ID3D10Texture2D*>(aTarget->GetNativeSurface(NATIVE_SURFACE_D3D10_TEXTURE));
if (!texture) {
return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget);
}
aTarget->Flush();
nsRefPtr<gfxASurface> surf =
new gfxD2DSurface(texture, ContentForFormat(aTarget->GetFormat()));
// add a reference to be held by the drawTarget
surf->AddRef();
aTarget->AddUserData(&ThebesSurfaceKey, surf.get(), DestroyThebesSurface);
/* "It might be worth it to clear cairo surfaces associated with a drawtarget.
The strong reference means for example for D2D that cairo's scratch surface
will be kept alive (well after a user being done) and consume extra VRAM.
We can deal with this in a follow-up though." */
// shouldn't this hold a reference?
surf->SetData(&kDrawTarget, aTarget, NULL);
return surf.forget();
if (!texture) {
return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget);
}
aTarget->Flush();
nsRefPtr<gfxASurface> surf =
new gfxD2DSurface(texture, ContentForFormat(aTarget->GetFormat()));
surf->SetData(&kDrawTarget, aTarget, NULL);
return surf.forget();
}
#endif

View File

@ -47,11 +47,8 @@ fails-if(Android) != text-font-lang.html text-font-lang-notref.html
== strokeText-path.html strokeText-path-ref.html
# azure quartz uses CGDrawLinearGradient instead of DrawShading
# so we have less control over degenerate behaviour as tested by this
# test
fails-if(azureQuartz) == linear-gradient-1a.html linear-gradient-1-ref.html
# gradient off-by-one, fails on windows and linux
== linear-gradient-1a.html linear-gradient-1-ref.html
fails-if(/Mac\x20OS\x20X\x2010\.[56]/.test(http.oscpu)) == linear-gradient-1b.html linear-gradient-1-ref.html
== zero-dimensions.html zero-dimensions-ref.html

View File

@ -1,9 +1,9 @@
fuzzy-if(azureQuartz) fails-if(Android) == linear-1a.html linear-1-ref.html
fuzzy-if(azureQuartz) fails-if(Android) == linear-1b.html linear-1-ref.html
fuzzy-if(azureQuartz) fails-if(Android) == linear-keywords-1a.html linear-keywords-1-ref.html
fuzzy-if(azureQuartz) fails-if(Android) == linear-keywords-1b.html linear-keywords-1-ref.html
fuzzy-if(azureQuartz) fails-if(Android) == linear-percent.html linear-percent-ref.html
fuzzy-if(azureQuartz) fails-if(Android) == linear-mix.html linear-mix-ref.html
fails-if(Android) == linear-1a.html linear-1-ref.html
fails-if(Android) == linear-1b.html linear-1-ref.html
fails-if(Android) == linear-keywords-1a.html linear-keywords-1-ref.html
fails-if(Android) == linear-keywords-1b.html linear-keywords-1-ref.html
fails-if(Android) == linear-percent.html linear-percent-ref.html
fails-if(Android) == linear-mix.html linear-mix-ref.html
== linear-diagonal-1a.html linear-diagonal-1-ref.html
== linear-diagonal-1b.html linear-diagonal-1-ref.html
== linear-diagonal-1c.html linear-diagonal-1-ref.html
@ -36,20 +36,20 @@ fails-if(d2d) == linear-repeat-1g.html linear-repeat-1-ref.html # bug 582236
== linear-stops-1d.html linear-stops-1-ref.html
== linear-stops-1e.html linear-stops-1-ref.html
== linear-stops-1f.html linear-stops-1-ref.html
fuzzy-if(azureQuartz) fails-if(Android) == linear-vertical-1a.html linear-vertical-1-ref.html
fuzzy-if(azureQuartz) fails-if(Android) == linear-vertical-1b.html linear-vertical-1-ref.html
fuzzy-if(azureQuartz) fails-if(Android) == linear-vertical-1c.html linear-vertical-1-ref.html
fuzzy-if(azureQuartz) fails-if(Android) == linear-vertical-1d.html linear-vertical-1-ref.html
fuzzy-if(azureQuartz) fails-if(Android) == linear-vertical-1e.html linear-vertical-1-ref.html
fails-if(Android) == linear-vertical-1a.html linear-vertical-1-ref.html
fails-if(Android) == linear-vertical-1b.html linear-vertical-1-ref.html
fails-if(Android) == linear-vertical-1c.html linear-vertical-1-ref.html
fails-if(Android) == linear-vertical-1d.html linear-vertical-1-ref.html
fails-if(Android) == linear-vertical-1e.html linear-vertical-1-ref.html
== linear-viewport.html linear-viewport-ref.html
== linear-zero-length-1a.html linear-zero-length-1-ref.html
== linear-zero-length-1b.html linear-zero-length-1-ref.html
== linear-zero-length-1c.html linear-zero-length-1-ref.html
== nostops.html about:blank
== onestop.html about:blank
fuzzy-if(azureQuartz) fails-if(Android) random-if(d2d) == radial-1a.html radial-1-ref.html
fuzzy-if(azureQuartz) fails-if(Android) == radial-2a.html radial-2-ref.html
fuzzy-if(azureQuartz) fails-if(Android) == radial-2b.html radial-2-ref.html
fails-if(Android) random-if(d2d) == radial-1a.html radial-1-ref.html
fails-if(Android) == radial-2a.html radial-2-ref.html
fails-if(Android) == radial-2b.html radial-2-ref.html
== radial-position-1a.html radial-position-1-ref.html
== radial-shape-closest-corner-1a.html radial-shape-closest-corner-1-ref.html
== radial-shape-closest-side-1a.html radial-shape-closest-side-1-ref.html
@ -77,23 +77,23 @@ fails-if(/Mac\x20OS\x20X\x2010\.[56]/.test(http.oscpu)) == twostops-1c.html twos
== twostops-1g.html twostops-1-ref.html
# from http://www.xanthir.com/:4bhipd by way of http://a-ja.net/newgrad.html
fuzzy-if(azureQuartz) fails-if(Android) == aja-linear-1a.html aja-linear-1-ref.html
fails-if(Android) == aja-linear-1a.html aja-linear-1-ref.html
fails-if(!d2d) == aja-linear-1b.html aja-linear-1-ref.html # bug 526694
fuzzy-if(azureQuartz) fails-if(Android) == aja-linear-1c.html aja-linear-1-ref.html
fuzzy-if(azureQuartz) fails-if(Android) == aja-linear-1d.html aja-linear-1-ref.html
fuzzy-if(azureQuartz) fails-if(Android) == aja-linear-1e.html aja-linear-1-ref.html
fuzzy-if(azureQuartz) fails-if(Android) == aja-linear-1f.html aja-linear-1-ref.html
fuzzy-if(azureQuartz) fails-if(Android) == aja-linear-1g.html aja-linear-1-ref.html
fuzzy-if(azureQuartz) fails-if(Android) == aja-linear-2a.html aja-linear-2-ref.html
fuzzy-if(azureQuartz) fails-if(Android) == aja-linear-2b.html aja-linear-2-ref.html
fails-if(Android) == aja-linear-1c.html aja-linear-1-ref.html
fails-if(Android) == aja-linear-1d.html aja-linear-1-ref.html
fails-if(Android) == aja-linear-1e.html aja-linear-1-ref.html
fails-if(Android) == aja-linear-1f.html aja-linear-1-ref.html
fails-if(Android) == aja-linear-1g.html aja-linear-1-ref.html
fails-if(Android) == aja-linear-2a.html aja-linear-2-ref.html
fails-if(Android) == aja-linear-2b.html aja-linear-2-ref.html
fails == aja-linear-2c.html aja-linear-2-ref.html # bug 522607
fails-if(!d2d) == aja-linear-2d.html aja-linear-2-ref.html # bug 526694
fuzzy-if(azureQuartz) fails-if(Android) == aja-linear-3a.html aja-linear-3-ref.html
fuzzy-if(azureQuartz) fails-if(Android) == aja-linear-3b.html aja-linear-3-ref.html
fuzzy-if(azureQuartz) fails-if(Android) == aja-linear-4a.html aja-linear-4-ref.html
fuzzy-if(azureQuartz) fails-if(Android) == aja-linear-4b.html aja-linear-4-ref.html
fuzzy-if(azureQuartz) fails-if(Android) == aja-linear-5a.html aja-linear-5-ref.html
fuzzy-if(azureQuartz) fails-if(Android) fails-if(/Mac\x20OS\x20X\x2010\.5/.test(http.oscpu)) == aja-linear-6a.html aja-linear-6-ref.html # bug 526708
fails-if(Android) == aja-linear-3a.html aja-linear-3-ref.html
fails-if(Android) == aja-linear-3b.html aja-linear-3-ref.html
fails-if(Android) == aja-linear-4a.html aja-linear-4-ref.html
fails-if(Android) == aja-linear-4b.html aja-linear-4-ref.html
fails-if(Android) == aja-linear-5a.html aja-linear-5-ref.html
fails-if(Android) fails-if(/Mac\x20OS\x20X\x2010\.5/.test(http.oscpu)) == aja-linear-6a.html aja-linear-6-ref.html # bug 526708
fails == aja-linear-6b.html aja-linear-6-ref.html # bug 522607
== height-dependence-1.html height-dependence-1-ref.html
fails-if(cocoaWidget) == height-dependence-2.html height-dependence-2-ref.html # bug 535007

View File

@ -1,6 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<div style="background: #ff00ff; width: 500px; height: 500px;"></div>
</body>
</html>

View File

@ -1,6 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<div style="background: #ff01ff; width: 500px; height: 500px;"></div>
</body>
</html>

View File

@ -129,10 +129,3 @@ pref(font.default.x-western,"sans-serif") == font-sans-serif.html font-default.h
pref(font.default.x-western,"sans-serif") != font-serif.html font-default.html
fails pref(font.default.x-western,true) == font-serif.html font-default.html
fails pref(font.default.x-western,0) == font-serif.html font-default.html
# reftest syntax: fuzzy
fuzzy == fuzzy.html fuzzy-ref.html
fuzzy != too-fuzzy.html fuzzy-ref.html
fuzzy-if(true) == fuzzy.html fuzzy-ref.html
fuzzy-if(false) == fuzzy-ref.html fuzzy-ref.html
# When using 565 fuzzy.html and fuzzy-ref.html will compare as equal
fails fuzzy-if(false) random-if(Android) == fuzzy.html fuzzy-ref.html

View File

@ -1,6 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<div style="background: #ff04ff; width: 500px; height: 500px;"></div>
</body>
</html>

View File

@ -39,7 +39,7 @@ fails == canvas-drawImage-scale-2a.html canvas-drawImage-scale-2-ref.html # XXX
fails == canvas-drawImage-scale-2b.html canvas-drawImage-scale-2-ref.html # XXX all edges fuzzy
== canvas-drawImage-slice-1a.html lime100x100-ref.html
fails-if(!azureQuartz) == canvas-drawImage-slice-1b.html lime100x100-ref.html # XXX all edges fuzzy
fails == canvas-drawImage-slice-1b.html lime100x100-ref.html # XXX all edges fuzzy
== canvas-drawImage-origin-clean-1.html lime100x100-ref.html

View File

@ -106,14 +106,6 @@ must be one of the following:
fast on a 32-bit system but inordinately slow on a
64-bit system).
fuzzy This allows a test to pass if the pixel value differences
are <= 2. It can also be used with '!=' to ensure that the
difference is greater than 2.
fuzzy-if(condition) If the condition is met, the test is treated as if
'fuzzy' had been specified. This is useful if there
are differences on particular platforms.
require-or(cond1&&cond2&&...,fallback)
Require some particular setup be performed or environmental
condition(s) made true (eg setting debug mode) before the test

View File

@ -39,7 +39,7 @@
import sys, os.path, re
commentRE = re.compile(r"\s+#")
conditionsRE = re.compile(r"^(fails|needs-focus|random|skip|asserts|fuzzy)")
conditionsRE = re.compile(r"^(fails|needs-focus|random|skip|asserts)")
httpRE = re.compile(r"HTTP\((\.\.(\/\.\.)*)\)")
protocolRE = re.compile(r"^\w+:")

View File

@ -149,7 +149,6 @@ const EXPECTED_PASS = 0;
const EXPECTED_FAIL = 1;
const EXPECTED_RANDOM = 2;
const EXPECTED_DEATH = 3; // test must be skipped to avoid e.g. crash/hang
const EXPECTED_FUZZY = 4;
// types of preference value we might want to set for a specific test
const PREF_BOOLEAN = 0;
@ -346,9 +345,13 @@ function InitAndStartRefTests()
gThisChunk = 0;
}
gWindowUtils = gContainingWindow.QueryInterface(CI.nsIInterfaceRequestor).getInterface(CI.nsIDOMWindowUtils);
if (!gWindowUtils || !gWindowUtils.compareCanvases)
throw "nsIDOMWindowUtils inteface missing";
try {
gWindowUtils = gContainingWindow.QueryInterface(CI.nsIInterfaceRequestor).getInterface(CI.nsIDOMWindowUtils);
if (gWindowUtils && !gWindowUtils.compareCanvases)
gWindowUtils = null;
} catch (e) {
gWindowUtils = null;
}
gIOService = CC[IO_SERVICE_CONTRACTID].getService(CI.nsIIOService);
gDebug = CC[DEBUG_CONTRACTID].getService(CI.nsIDebug2);
@ -509,20 +512,18 @@ function BuildConditionSandbox(aURL) {
} catch(e) {
sandbox.xulRuntime.XPCOMABI = "";
}
var gfxInfo = (NS_GFXINFO_CONTRACTID in CC) && CC[NS_GFXINFO_CONTRACTID].getService(CI.nsIGfxInfo);
try {
sandbox.d2d = gfxInfo.D2DEnabled;
} catch (e) {
sandbox.d2d = false;
// nsIGfxInfo is currently only implemented on Windows
sandbox.d2d = (NS_GFXINFO_CONTRACTID in CC) && CC[NS_GFXINFO_CONTRACTID].getService(CI.nsIGfxInfo).D2DEnabled;
} catch(e) {
sandbox.d2d = false;
}
sandbox.azureQuartz = gfxInfo.getInfo().AzureBackend == "quartz";
sandbox.layersGPUAccelerated =
gWindowUtils.layerManagerType != "Basic";
gWindowUtils && gWindowUtils.layerManagerType != "Basic";
sandbox.layersOpenGL =
gWindowUtils.layerManagerType == "OpenGL";
gWindowUtils && gWindowUtils.layerManagerType == "OpenGL";
// Shortcuts for widget toolkits.
sandbox.Android = xr.OS == "Android";
@ -689,16 +690,16 @@ function ReadManifest(aURL, inherited_status)
var slow = false;
var prefSettings = [];
while (items[0].match(/^(fails|needs-focus|random|skip|asserts|slow|require-or|silentfail|pref|fuzzy)/)) {
while (items[0].match(/^(fails|needs-focus|random|skip|asserts|slow|require-or|silentfail|pref)/)) {
var item = items.shift();
var stat;
var cond;
var m = item.match(/^(fails|random|skip|silentfail|fuzzy)-if(\(.*\))$/);
var m = item.match(/^(fails|random|skip|silentfail)-if(\(.*\))$/);
if (m) {
stat = m[1];
// Note: m[2] contains the parentheses, and we want them.
cond = Components.utils.evalInSandbox(m[2], sandbox);
} else if (item.match(/^(fails|random|skip|fuzzy)$/)) {
} else if (item.match(/^(fails|random|skip)$/)) {
stat = item;
cond = true;
} else if (item == "needs-focus") {
@ -780,8 +781,6 @@ function ReadManifest(aURL, inherited_status)
expected_status = EXPECTED_RANDOM;
} else if (stat == "skip") {
expected_status = EXPECTED_DEATH;
} else if (stat == "fuzzy") {
expected_status = EXPECTED_FUZZY;
} else if (stat == "silentfail") {
allow_silent_fail = true;
}
@ -1301,8 +1300,6 @@ function RecordResult(testRunTime, errorMsg, scriptResults)
true: {s: "TEST-PASS" + randomMsg , n: "Random"},
false: {s: "TEST-KNOWN-FAIL" + randomMsg, n: "Random"}
};
outputs[EXPECTED_FUZZY] = outputs[EXPECTED_PASS];
var output;
if (gURLs[0].type == TYPE_LOAD) {
@ -1405,25 +1402,21 @@ function RecordResult(testRunTime, errorMsg, scriptResults)
var differences;
// whether the two renderings match:
var equal;
var maxDifference = {};
differences = gWindowUtils.compareCanvases(gCanvas1, gCanvas2, maxDifference);
equal = (differences == 0);
// what is expected on this platform (PASS, FAIL, or RANDOM)
var expected = gURLs[0].expected;
if (maxDifference.value > 0 && maxDifference.value <= 2) {
if (equal) {
throw "Inconsistent result from compareCanvases.";
}
equal = expected == EXPECTED_FUZZY;
gDumpLog("REFTEST fuzzy match\n");
if (gWindowUtils) {
differences = gWindowUtils.compareCanvases(gCanvas1, gCanvas2, {});
equal = (differences == 0);
} else {
differences = -1;
var k1 = gCanvas1.toDataURL();
var k2 = gCanvas2.toDataURL();
equal = (k1 == k2);
}
// whether the comparison result matches what is in the manifest
var test_passed = (equal == (gURLs[0].type == TYPE_REFTEST_EQUAL));
// what is expected on this platform (PASS, FAIL, or RANDOM)
var expected = gURLs[0].expected;
output = outputs[expected][test_passed];
++gTestResults[output.n];
@ -1441,12 +1434,11 @@ function RecordResult(testRunTime, errorMsg, scriptResults)
gDumpLog(result + "\n");
if (!test_passed && expected == EXPECTED_PASS ||
!test_passed && expected == EXPECTED_FUZZY ||
test_passed && expected == EXPECTED_FAIL) {
if (!equal) {
gDumpLog("REFTEST IMAGE 1 (TEST): " + gCanvas1.toDataURL() + "\n");
gDumpLog("REFTEST IMAGE 2 (REFERENCE): " + gCanvas2.toDataURL() + "\n");
gDumpLog("REFTEST number of differing pixels: " + differences + " max difference: " + maxDifference.value + "\n");
gDumpLog("REFTEST number of differing pixels: " + differences + "\n");
} else {
gDumpLog("REFTEST IMAGE: " + gCanvas1.toDataURL() + "\n");
}

View File

@ -230,10 +230,6 @@ pref("gfx.font_rendering.directwrite.use_gdi_table_loading", true);
#ifdef XP_WIN
pref("gfx.canvas.azure.enabled", true);
#else
#ifdef XP_MACOSX
pref("gfx.canvas.azure.enabled", true);
#endif
#endif
pref("accessibility.browsewithcaret", false);