Backed out 5 changesets (bug 1456555) for reftests failuress on /reftests/svg/text/pattern-content.svg.
authorBrindusan Cristian <cbrindusan@mozilla.com>
Tue, 06 Nov 2018 07:39:19 +0200
changeset 444536 b765559ddc3a9d0b54f3665de95407799e58e317
parent 444535 50f1edbfb52c2dd1e8074c29bf0d00c5ad08e2f7
child 444537 b4e4e74aa3ccb6673df2a4b62249706e5999fcd6
push id34996
push userrgurzau@mozilla.com
push dateTue, 06 Nov 2018 09:53:23 +0000
treeherdermozilla-central@e160f0a60e4f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1456555
milestone65.0a1
backs out0f2854553c211d9046d7c4161a696cdd6386185a
5e3b20a1916210c1a6b80145ffa541355bd14cf5
6cc965ecc095884493be180447436aa038d757ca
595abbb5bf3e172e1f1fda63a29a612b2b27751d
c4df6309a5bee9faf8a39218e984341a579a4da6
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 5 changesets (bug 1456555) for reftests failuress on /reftests/svg/text/pattern-content.svg. Backed out changeset 0f2854553c21 (bug 1456555) Backed out changeset 5e3b20a19162 (bug 1456555) Backed out changeset 6cc965ecc095 (bug 1456555) Backed out changeset 595abbb5bf3e (bug 1456555) Backed out changeset c4df6309a5be (bug 1456555)
gfx/2d/2D.h
gfx/2d/DrawTargetOffset.cpp
gfx/2d/DrawTargetOffset.h
gfx/2d/DrawTargetSkia.cpp
gfx/2d/SourceSurfaceD2D1.cpp
gfx/2d/SourceSurfaceD2D1.h
gfx/2d/SourceSurfaceRawData.h
gfx/2d/SourceSurfaceSkia.cpp
gfx/2d/SourceSurfaceSkia.h
gfx/layers/SourceSurfaceSharedData.h
gfx/layers/SourceSurfaceVolatileData.h
gfx/layers/wr/WebRenderCommandBuilder.cpp
gfx/webrender_bindings/src/bindings.rs
layout/reftests/svg/reftest.list
layout/reftests/text-stroke/reftest.list
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -26,17 +26,16 @@
 
 // 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.
 #include "mozilla/RefPtr.h"
 #include "mozilla/StaticMutex.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/ThreadSafeWeakPtr.h"
-#include "mozilla/Atomics.h"
 
 #include "mozilla/DebugOnly.h"
 
 #include "nsRegionFwd.h"
 
 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK)
   #ifndef MOZ_ENABLE_FREETYPE
   #define MOZ_ENABLE_FREETYPE
@@ -441,24 +440,24 @@ protected:
   UserData mUserData;
 };
 
 class DataSourceSurface : public SourceSurface
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurface, override)
   DataSourceSurface()
-    : mMapCount(0)
+    : mIsMapped(false)
   {
   }
 
 #ifdef DEBUG
   virtual ~DataSourceSurface()
   {
-    MOZ_ASSERT(mMapCount == 0);
+    MOZ_ASSERT(!mIsMapped, "Someone forgot to call Unmap()");
   }
 #endif
 
   struct MappedSurface {
     uint8_t *mData;
     int32_t mStride;
   };
 
@@ -553,41 +552,29 @@ public:
    * Stride of the surface, distance in bytes between the start of the image
    * data belonging to row y and row y+1. This may be negative.
    * Can return 0 if there was OOM allocating surface data.
    */
   virtual int32_t Stride() = 0;
 
   /**
    * The caller is responsible for ensuring aMappedSurface is not null.
-  // Althought Map (and Moz2D in general) isn't normally threadsafe,
-  // we want to allow it for SourceSurfaceRawData since it should
-  // always be fine (for reading at least).
-  //
-  // This is the same as the base class implementation except using
-  // mMapCount instead of mIsMapped since that breaks for multithread.
-  //
-  // Once mfbt supports Monitors we should implement proper read/write
-  // locking to prevent write races.
    */
   virtual bool Map(MapType, MappedSurface *aMappedSurface)
   {
     aMappedSurface->mData = GetData();
     aMappedSurface->mStride = Stride();
-    bool success = !!aMappedSurface->mData;
-    if (success) {
-      mMapCount++;
-    }
-    return success;
+    mIsMapped = !!aMappedSurface->mData;
+    return mIsMapped;
   }
 
   virtual void Unmap()
   {
-    mMapCount--;
-    MOZ_ASSERT(mMapCount >= 0);
+    MOZ_ASSERT(mIsMapped);
+    mIsMapped = false;
   }
 
   /**
    * Returns a DataSourceSurface with the same data as this one, but
    * guaranteed to have surface->GetType() == SurfaceType::DATA.
    *
    * The returning surface might be null, because of OOM or gfx device reset.
    * The caller needs to do null-check before using it.
@@ -622,17 +609,17 @@ public:
   }
 
   /**
    * Indicate a region which has changed in the surface.
    */
   virtual void Invalidate(const IntRect& aDirtyRect) { }
 
 protected:
-  Atomic<int32_t> mMapCount;
+  bool mIsMapped;
 };
 
 /** This is an abstract object that accepts path segments. */
 class PathSink : public RefCounted<PathSink>
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathSink)
   virtual ~PathSink() {}
--- a/gfx/2d/DrawTargetOffset.cpp
+++ b/gfx/2d/DrawTargetOffset.cpp
@@ -78,37 +78,30 @@ OFFSET_COMMAND4(MaskSurface, const Patte
 OFFSET_COMMAND4(FillGlyphs, ScaledFont*, const GlyphBuffer&, const Pattern&, const DrawOptions&)
 OFFSET_COMMAND3(Mask, const Pattern&, const Pattern&, const DrawOptions&)
 
 void
 DrawTargetOffset::DrawFilter(FilterNode* aNode, const Rect& aSourceRect, const Point& aDestPoint, const DrawOptions& aOptions)
 {
   auto clone = mTransform;
   bool invertible = clone.Invert();
-  // aSourceRect is in filter space. The filter outputs from aSourceRect need
-  // to be drawn at aDestPoint in user space.
-  Rect userSpaceSource = Rect(aDestPoint, aSourceRect.Size());
+  auto src = aSourceRect;
   if (invertible) {
     // Try to reduce the source rect so that it's not much bigger
     // than the draw target. The result is not minimal. Examples
     // are left as an exercise for the reader.
     auto destRect = Rect(mOrigin.x,
                          mOrigin.y,
                          mDrawTarget->GetSize().width,
                          mDrawTarget->GetSize().height);
-    Rect userSpaceBounds = clone.TransformBounds(destRect);
-    userSpaceSource = userSpaceSource.Intersect(userSpaceBounds);
+    auto dtBounds = clone.TransformBounds(destRect);
+    src = aSourceRect.Intersect(dtBounds);
   }
-
-  // Compute how much we moved the top-left of the source rect by, and use that
-  // to compute the new dest point, and move our intersected source rect back
-  // into the (new) filter space.
-  Point shift = userSpaceSource.TopLeft() - aDestPoint;
-  Rect filterSpaceSource = Rect(aSourceRect.TopLeft() + shift, userSpaceSource.Size());
-  mDrawTarget->DrawFilter(aNode, filterSpaceSource, aDestPoint + shift, aOptions);
+  auto shift = src.TopLeft() - aSourceRect.TopLeft();
+  mDrawTarget->DrawFilter(aNode, src, aDestPoint + shift, aOptions);
 }
 
 void
 DrawTargetOffset::PushClip(const Path* aPath)
 {
   mDrawTarget->PushClip(aPath);
 }
 
@@ -186,37 +179,34 @@ DrawTargetOffset::Fill(const Path* aPath
   mDrawTarget->Fill(aPath, aPattern, aDrawOptions);
 }
 
 void
 DrawTargetOffset::PushLayer(bool aOpaque, Float aOpacity, SourceSurface* aMask,
                            const Matrix& aMaskTransform, const IntRect& aBounds,
                            bool aCopyBackground)
 {
-  IntRect bounds = aBounds - mOrigin;
-
+  IntRect bounds = aBounds;
+  bounds.MoveBy(mOrigin);
   mDrawTarget->PushLayer(aOpaque, aOpacity, aMask, aMaskTransform, bounds, aCopyBackground);
-  SetPermitSubpixelAA(mDrawTarget->GetPermitSubpixelAA());
 }
 
 void
 DrawTargetOffset::PushLayerWithBlend(bool aOpaque, Float aOpacity,
                                     SourceSurface* aMask,
                                     const Matrix& aMaskTransform,
                                     const IntRect& aBounds,
                                     bool aCopyBackground,
                                     CompositionOp aOp)
 {
-  IntRect bounds = aBounds - mOrigin;
-
+  IntRect bounds = aBounds;
+  bounds.MoveBy(mOrigin);
   mDrawTarget->PushLayerWithBlend(aOpaque, aOpacity, aMask, aMaskTransform, bounds, aCopyBackground, aOp);
-  SetPermitSubpixelAA(mDrawTarget->GetPermitSubpixelAA());
 }
 
 void
 DrawTargetOffset::PopLayer()
 {
   mDrawTarget->PopLayer();
-  SetPermitSubpixelAA(mDrawTarget->GetPermitSubpixelAA());
 }
 
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/2d/DrawTargetOffset.h
+++ b/gfx/2d/DrawTargetOffset.h
@@ -33,17 +33,17 @@ public:
   virtual DrawTargetType GetType() const override { return mDrawTarget->GetType(); }
   virtual BackendType GetBackendType() const override { return mDrawTarget->GetBackendType(); }
   virtual already_AddRefed<SourceSurface> Snapshot() override;
   virtual void DetachAllSnapshots() override;
   virtual IntSize GetSize() const override {
     return mDrawTarget->GetSize();
   }
   virtual IntRect GetRect() const override {
-    return IntRect(mOrigin, GetSize());
+    return mDrawTarget->GetRect();
   }
 
   virtual void Flush() override;
   virtual void DrawSurface(SourceSurface *aSurface,
                            const Rect &aDest,
                            const Rect &aSource,
                            const DrawSurfaceOptions &aSurfOptions,
                            const DrawOptions &aOptions) override;
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -2120,20 +2120,16 @@ DrawTargetSkia::PushLayerWithBlend(bool 
     } else {
       bounds.setEmpty();
     }
   }
 
   sk_sp<SkImage> clipImage = aMask ? GetSkImageForSurface(aMask) : nullptr;
   SkMatrix clipMatrix;
   GfxMatrixToSkiaMatrix(aMaskTransform, clipMatrix);
-  if (aMask) {
-    clipMatrix.postTranslate(aMask->GetRect().X(), aMask->GetRect().Y());
-  }
-
   SkCanvas::SaveLayerRec saveRec(aBounds.IsEmpty() ? nullptr : &bounds,
                                  &paint,
                                  nullptr,
                                  clipImage.get(),
                                  &clipMatrix,
                                  SkCanvas::kPreserveLCDText_SaveLayerFlag |
                                    (aCopyBackground ? SkCanvas::kInitWithPrevious_SaveLayerFlag : 0));
 
--- a/gfx/2d/SourceSurfaceD2D1.cpp
+++ b/gfx/2d/SourceSurfaceD2D1.cpp
@@ -159,24 +159,23 @@ SourceSurfaceD2D1::MarkIndependent()
     mDrawTarget->mSnapshot = nullptr;
     mDrawTarget = nullptr;
   }
 }
 
 DataSourceSurfaceD2D1::DataSourceSurfaceD2D1(ID2D1Bitmap1 *aMappableBitmap, SurfaceFormat aFormat)
   : mBitmap(aMappableBitmap)
   , mFormat(aFormat)
-  , mIsMapped(false)
-  , mImplicitMapped(false)
+  , mMapped(false)
 {
 }
 
 DataSourceSurfaceD2D1::~DataSourceSurfaceD2D1()
 {
-  if (mImplicitMapped) {
+  if (mMapped) {
     mBitmap->Unmap();
   }
 }
 
 IntSize
 DataSourceSurfaceD2D1::GetSize() const
 {
   D2D1_SIZE_F size = mBitmap->GetSize();
@@ -191,17 +190,17 @@ DataSourceSurfaceD2D1::GetData()
 
   return mMap.bits;
 }
 
 bool
 DataSourceSurfaceD2D1::Map(MapType aMapType, MappedSurface *aMappedSurface)
 {
   // DataSourceSurfaces used with the new Map API should not be used with GetData!!
-  MOZ_ASSERT(!mImplicitMapped);
+  MOZ_ASSERT(!mMapped);
   MOZ_ASSERT(!mIsMapped);
 
   D2D1_MAP_OPTIONS options;
   if (aMapType == MapType::READ) {
     options = D2D1_MAP_OPTIONS_READ;
   } else {
     gfxWarning() << "Attempt to map D2D1 DrawTarget for writing.";
     return false;
@@ -236,20 +235,20 @@ DataSourceSurfaceD2D1::Stride()
   return mMap.pitch;
 }
 
 void
 DataSourceSurfaceD2D1::EnsureMapped()
 {
   // Do not use GetData() after having used Map!
   MOZ_ASSERT(!mIsMapped);
-  if (mImplicitMapped) {
+  if (mMapped) {
     return;
   }
   if (FAILED(mBitmap->Map(D2D1_MAP_OPTIONS_READ, &mMap))) {
     gfxCriticalError() << "Failed to map bitmap (EM).";
     return;
   }
-  mImplicitMapped = true;
+  mMapped = true;
 }
 
 }
 }
--- a/gfx/2d/SourceSurfaceD2D1.h
+++ b/gfx/2d/SourceSurfaceD2D1.h
@@ -85,16 +85,15 @@ public:
 
 private:
   friend class SourceSurfaceD2DTarget;
   void EnsureMapped();
 
   mutable RefPtr<ID2D1Bitmap1> mBitmap;
   SurfaceFormat mFormat;
   D2D1_MAPPED_RECT mMap;
-  bool mIsMapped;
-  bool mImplicitMapped;
+  bool mMapped;
 };
 
 }
 }
 
 #endif /* MOZILLA_GFX_SOURCESURFACED2D2TARGET_H_ */
--- a/gfx/2d/SourceSurfaceRawData.h
+++ b/gfx/2d/SourceSurfaceRawData.h
@@ -18,41 +18,70 @@ class SourceSurfaceRawData : public Data
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceRawData, override)
 
   SourceSurfaceRawData()
     : mRawData(0)
     , mStride(0)
     , mFormat(SurfaceFormat::UNKNOWN)
+    , mMapCount(0)
     , mOwnData(false)
     , mDeallocator(nullptr)
     , mClosure(nullptr)
   {
   }
 
   virtual ~SourceSurfaceRawData()
   {
     if (mDeallocator) {
       mDeallocator(mClosure);
     } else if (mOwnData) {
       // The buffer is created from GuaranteePersistance().
       delete [] mRawData;
     }
+
+    MOZ_ASSERT(mMapCount == 0);
   }
 
   virtual uint8_t *GetData() override { return mRawData; }
   virtual int32_t Stride() override { return mStride; }
 
   virtual SurfaceType GetType() const override { return SurfaceType::DATA; }
   virtual IntSize GetSize() const override { return mSize; }
   virtual SurfaceFormat GetFormat() const override { return mFormat; }
 
   virtual void GuaranteePersistance() override;
 
+  // Althought Map (and Moz2D in general) isn't normally threadsafe,
+  // we want to allow it for SourceSurfaceRawData since it should
+  // always be fine (for reading at least).
+  //
+  // This is the same as the base class implementation except using
+  // mMapCount instead of mIsMapped since that breaks for multithread.
+  //
+  // Once mfbt supports Monitors we should implement proper read/write
+  // locking to prevent write races.
+  virtual bool Map(MapType, MappedSurface *aMappedSurface) override
+  {
+    aMappedSurface->mData = GetData();
+    aMappedSurface->mStride = Stride();
+    bool success = !!aMappedSurface->mData;
+    if (success) {
+      mMapCount++;
+    }
+    return success;
+  }
+
+  virtual void Unmap() override
+  {
+    mMapCount--;
+    MOZ_ASSERT(mMapCount >= 0);
+  }
+
 private:
   friend class Factory;
 
   // If we have a custom deallocator, the |aData| will be released using the
   // custom deallocator and |aClosure| in dtor.  The assumption is that the
   // caller will check for valid size and stride before making this call.
   void InitWrappingData(unsigned char *aData,
                         const IntSize &aSize,
@@ -60,32 +89,35 @@ private:
                         SurfaceFormat aFormat,
                         Factory::SourceSurfaceDeallocator aDeallocator,
                         void* aClosure);
 
   uint8_t *mRawData;
   int32_t mStride;
   SurfaceFormat mFormat;
   IntSize mSize;
+  Atomic<int32_t> mMapCount;
 
   bool mOwnData;
   Factory::SourceSurfaceDeallocator mDeallocator;
   void* mClosure;
 };
 
 class SourceSurfaceAlignedRawData : public DataSourceSurface
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceAlignedRawData, override)
   SourceSurfaceAlignedRawData()
     : mStride(0)
     , mFormat(SurfaceFormat::UNKNOWN)
+    , mMapCount(0)
   {}
   ~SourceSurfaceAlignedRawData()
   {
+    MOZ_ASSERT(mMapCount == 0);
   }
 
   bool Init(const IntSize &aSize,
             SurfaceFormat aFormat,
             bool aClearMem,
             uint8_t aClearValue,
             int32_t aStride = 0);
 
@@ -97,21 +129,39 @@ public:
   virtual SurfaceFormat GetFormat() const override { return mFormat; }
 
   void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
                               size_t& aHeapSizeOut,
                               size_t& aNonHeapSizeOut,
                               size_t& aExtHandlesOut,
                               uint64_t& aExtIdOut) const override;
 
+  virtual bool Map(MapType, MappedSurface *aMappedSurface) override
+  {
+    aMappedSurface->mData = GetData();
+    aMappedSurface->mStride = Stride();
+    bool success = !!aMappedSurface->mData;
+    if (success) {
+      mMapCount++;
+    }
+    return success;
+  }
+
+  virtual void Unmap() override
+  {
+    mMapCount--;
+    MOZ_ASSERT(mMapCount >= 0);
+  }
+
 private:
   friend class Factory;
 
   AlignedArray<uint8_t> mArray;
   int32_t mStride;
   SurfaceFormat mFormat;
   IntSize mSize;
+  Atomic<int32_t> mMapCount;
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_SOURCESURFACERAWDATA_H_ */
--- a/gfx/2d/SourceSurfaceSkia.cpp
+++ b/gfx/2d/SourceSurfaceSkia.cpp
@@ -18,17 +18,16 @@ using namespace std;
 namespace mozilla {
 namespace gfx {
 
 SourceSurfaceSkia::SourceSurfaceSkia()
   : mFormat(SurfaceFormat::UNKNOWN)
   , mStride(0)
   , mDrawTarget(nullptr)
   , mChangeMutex("SourceSurfaceSkia::mChangeMutex")
-  , mIsMapped(false)
 {
 }
 
 SourceSurfaceSkia::~SourceSurfaceSkia()
 {
 }
 
 IntSize
--- a/gfx/2d/SourceSurfaceSkia.h
+++ b/gfx/2d/SourceSurfaceSkia.h
@@ -68,15 +68,14 @@ private:
   sk_sp<SkImage> mImage;
   // This keeps a surface alive if needed because its DrawTarget has gone away.
   sk_sp<SkSurface> mSurface;
   SurfaceFormat mFormat;
   IntSize mSize;
   int32_t mStride;
   DrawTargetSkia* mDrawTarget;
   Mutex mChangeMutex;
-  bool mIsMapped;
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_SOURCESURFACESKIA_H_ */
--- a/gfx/layers/SourceSurfaceSharedData.h
+++ b/gfx/layers/SourceSurfaceSharedData.h
@@ -133,16 +133,17 @@ class SourceSurfaceSharedData final : pu
   typedef mozilla::ipc::SharedMemoryBasic SharedMemoryBasic;
 
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceSharedData, override)
 
   SourceSurfaceSharedData()
     : mMutex("SourceSurfaceSharedData")
     , mStride(0)
+    , mMapCount(0)
     , mHandleCount(0)
     , mFormat(SurfaceFormat::UNKNOWN)
     , mClosed(false)
     , mFinalized(false)
     , mShared(false)
   {
   }
 
@@ -320,16 +321,17 @@ public:
     RefPtr<SourceSurfaceSharedData> mSurface;
   };
 
 private:
   friend class SourceSurfaceSharedDataWrapper;
 
   ~SourceSurfaceSharedData() override
   {
+    MOZ_ASSERT(mMapCount == 0);
   }
 
   void LockHandle()
   {
     MutexAutoLock lock(mMutex);
     ++mHandleCount;
   }
 
@@ -357,16 +359,17 @@ private:
   /**
    * Attempt to close the handle. Only if the buffer has been both finalized
    * and we have completed sharing will it be released.
    */
   void CloseHandleInternal();
 
   mutable Mutex mMutex;
   int32_t mStride;
+  int32_t mMapCount;
   int32_t mHandleCount;
   Maybe<IntRect> mDirtyRect;
   IntSize mSize;
   RefPtr<SharedMemoryBasic> mBuf;
   RefPtr<SharedMemoryBasic> mOldBuf;
   SurfaceFormat mFormat;
   bool mClosed : 1;
   bool mFinalized : 1;
--- a/gfx/layers/SourceSurfaceVolatileData.h
+++ b/gfx/layers/SourceSurfaceVolatileData.h
@@ -26,16 +26,17 @@ namespace gfx {
 class SourceSurfaceVolatileData : public DataSourceSurface
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceVolatileData, override)
 
   SourceSurfaceVolatileData()
     : mMutex("SourceSurfaceVolatileData")
     , mStride(0)
+    , mMapCount(0)
     , mFormat(SurfaceFormat::UNKNOWN)
     , mWasPurged(false)
   {
   }
 
   bool Init(const IntSize &aSize,
             int32_t aStride,
             SurfaceFormat aFormat);
@@ -93,20 +94,22 @@ public:
     if (--mMapCount == 0) {
       mVBufPtr = nullptr;
     }
   }
 
 private:
   ~SourceSurfaceVolatileData() override
   {
+    MOZ_ASSERT(mMapCount == 0);
   }
 
   Mutex mMutex;
   int32_t mStride;
+  int32_t mMapCount;
   IntSize mSize;
   RefPtr<VolatileBuffer> mVBuf;
   VolatileBufferPtr<uint8_t> mVBufPtr;
   SurfaceFormat mFormat;
   bool mWasPurged;
 };
 
 } // namespace gfx
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -333,19 +333,16 @@ struct DIGroup
   IntRect mInvalidRect;
   nsRect mGroupBounds;
   LayerIntRect mPaintRect;
   int32_t mAppUnitsPerDevPixel;
   gfx::Size mScale;
   ScrollableLayerGuid::ViewID mScrollId;
   LayerPoint mResidualOffset;
   LayerIntRect mLayerBounds;
-  // The current bounds of the blob image, relative to
-  // the top-left of the mLayerBounds.
-  IntRect mImageBounds;
   Maybe<wr::ImageKey> mKey;
   std::vector<RefPtr<SourceSurface>> mExternalSurfaces;
   std::vector<RefPtr<ScaledFont>> mFonts;
 
   DIGroup()
     : mAppUnitsPerDevPixel(0)
     , mScrollId(ScrollableLayerGuid::NULL_SCROLL_ID)
   {
@@ -405,39 +402,42 @@ struct DIGroup
     const DisplayItemClip& clip = aItem->GetClip();
 
     int32_t appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
     MOZ_RELEASE_ASSERT(mAppUnitsPerDevPixel == appUnitsPerDevPixel);
     LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(mGroupBounds, appUnitsPerDevPixel);
     LayoutDeviceIntPoint offset = RoundedToInt(bounds.TopLeft());
     GP("\n");
     GP("CGC offset %d %d\n", offset.x, offset.y);
-    GP("imageRect %d %d %d %d\n", mImageBounds.x, mImageBounds.y, mImageBounds.width, mImageBounds.height);
+    LayerIntSize size = mLayerBounds.Size();
+    IntRect imageRect(0, 0, size.width, size.height);
+    GP("imageSize: %d %d\n", size.width, size.height);
     /*if (aItem->IsReused() && aData->mGeometry) {
       return;
     }*/
     aData->mInvalidRegion = false;
 
     GP("pre mInvalidRect: %s %p-%d - inv: %d %d %d %d\n", aItem->Name(), aItem->Frame(), aItem->GetPerFrameKey(),
        mInvalidRect.x, mInvalidRect.y, mInvalidRect.width, mInvalidRect.height);
     if (!aData->mGeometry) {
       // This item is being added for the first time, invalidate its entire area.
       UniquePtr<nsDisplayItemGeometry> geometry(aItem->AllocateGeometry(aBuilder));
       combined = clip.ApplyNonRoundedIntersection(geometry->ComputeInvalidationRegion());
       aData->mGeometry = std::move(geometry);
       nsRect bounds = combined.GetBounds();
 
       IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mLayerBounds.TopLeft());
-      aData->mRect = transformedRect.Intersect(mImageBounds);
+      aData->mRect = transformedRect.Intersect(imageRect);
       GP("CGC %s %d %d %d %d\n", aItem->Name(), bounds.x, bounds.y, bounds.width, bounds.height);
       GP("%d %d,  %f %f\n", mLayerBounds.TopLeft().x, mLayerBounds.TopLeft().y, aMatrix._11, aMatrix._22);
       GP("mRect %d %d %d %d\n", aData->mRect.x, aData->mRect.y, aData->mRect.width, aData->mRect.height);
       InvalidateRect(aData->mRect);
       aData->mInvalid = true;
     } else if (aData->mInvalid || /* XXX: handle image load invalidation */ (aItem->IsInvalid(invalid) && invalid.IsEmpty())) {
+      MOZ_RELEASE_ASSERT(imageRect.IsEqualEdges(aData->mImageRect));
       MOZ_RELEASE_ASSERT(mLayerBounds.TopLeft() == aData->mGroupOffset);
       UniquePtr<nsDisplayItemGeometry> geometry(aItem->AllocateGeometry(aBuilder));
       /* Instead of doing this dance, let's just invalidate the old rect and the
        * new rect.
       combined = aData->mClip.ApplyNonRoundedIntersection(aData->mGeometry->ComputeInvalidationRegion());
       combined.MoveBy(shift);
       combined.Or(combined, clip.ApplyNonRoundedIntersection(geometry->ComputeInvalidationRegion()));
       aData->mGeometry = std::move(geometry);
@@ -447,45 +447,46 @@ struct DIGroup
 
       GP("matrix: %f %f\n", aMatrix._31, aMatrix._32); 
       GP("frame invalid invalidate: %s\n", aItem->Name());
       GP("old rect: %d %d %d %d\n",
              aData->mRect.x,
              aData->mRect.y,
              aData->mRect.width,
              aData->mRect.height);
-      InvalidateRect(aData->mRect.Intersect(mImageBounds));
+      InvalidateRect(aData->mRect.Intersect(imageRect));
       // We want to snap to outside pixels. When should we multiply by the matrix?
       // XXX: TransformBounds is expensive. We should avoid doing it if we have no transform
       IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mLayerBounds.TopLeft());
-      aData->mRect = transformedRect.Intersect(mImageBounds);
+      aData->mRect = transformedRect.Intersect(imageRect);
       InvalidateRect(aData->mRect);
       GP("new rect: %d %d %d %d\n",
              aData->mRect.x,
              aData->mRect.y,
              aData->mRect.width,
              aData->mRect.height);
       aData->mInvalid = true;
     } else {
+      MOZ_RELEASE_ASSERT(imageRect.IsEqualEdges(aData->mImageRect));
       MOZ_RELEASE_ASSERT(mLayerBounds.TopLeft() == aData->mGroupOffset);
       GP("else invalidate: %s\n", aItem->Name());
       // this includes situations like reflow changing the position
       aItem->ComputeInvalidationRegion(aBuilder, aData->mGeometry.get(), &combined);
       if (!combined.IsEmpty()) {
         // There might be no point in doing this elaborate tracking here to get
         // smaller areas
-        InvalidateRect(aData->mRect.Intersect(mImageBounds)); // invalidate the old area -- in theory combined should take care of this
+        InvalidateRect(aData->mRect.Intersect(imageRect)); // invalidate the old area -- in theory combined should take care of this
         UniquePtr<nsDisplayItemGeometry> geometry(aItem->AllocateGeometry(aBuilder));
         // invalidate the invalidated area.
 
         aData->mGeometry = std::move(geometry);
 
         combined = clip.ApplyNonRoundedIntersection(aData->mGeometry->ComputeInvalidationRegion());
         IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mLayerBounds.TopLeft());
-        aData->mRect = transformedRect.Intersect(mImageBounds);
+        aData->mRect = transformedRect.Intersect(imageRect);
         InvalidateRect(aData->mRect);
 
         // CGC invariant broken
         if (!mInvalidRect.Contains(aData->mRect)) {
           gfxCriticalError() << "CGC-" <<
             "-" << aData->mRect.x <<
             "-" << aData->mRect.y <<
             "-" << aData->mRect.width <<
@@ -503,18 +504,18 @@ struct DIGroup
             // returning any change. Other items shouldn't have any hidden
             // geometry change.
             MOZ_RELEASE_ASSERT(geometry->mBounds.IsEqualEdges(aData->mGeometry->mBounds));
           } else {
             aData->mGeometry = std::move(geometry);
           }
           combined = clip.ApplyNonRoundedIntersection(aData->mGeometry->ComputeInvalidationRegion());
           IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mLayerBounds.TopLeft());
-          InvalidateRect(aData->mRect.Intersect(mImageBounds));
-          aData->mRect = transformedRect.Intersect(mImageBounds);
+          InvalidateRect(aData->mRect.Intersect(imageRect));
+          aData->mRect = transformedRect.Intersect(imageRect);
           InvalidateRect(aData->mRect);
 
           GP("ClipChange: %s %d %d %d %d\n", aItem->Name(),
                  aData->mRect.x, aData->mRect.y, aData->mRect.XMost(), aData->mRect.YMost());
 
         } else if (!aMatrix.ExactlyEquals(aData->mMatrix)) {
           // We haven't detected any changes so far. Unfortunately we don't
           // currently have a good way of checking if the transform has changed
@@ -527,52 +528,58 @@ struct DIGroup
             // the bounds of layer items can change on us
             // other items shouldn't
             MOZ_RELEASE_ASSERT(geometry->mBounds.IsEqualEdges(aData->mGeometry->mBounds));
           } else {
             aData->mGeometry = std::move(geometry);
           }
           combined = clip.ApplyNonRoundedIntersection(aData->mGeometry->ComputeInvalidationRegion());
           IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mLayerBounds.TopLeft());
-          InvalidateRect(aData->mRect.Intersect(mImageBounds));
-          aData->mRect = transformedRect.Intersect(mImageBounds);
+          InvalidateRect(aData->mRect.Intersect(imageRect));
+          aData->mRect = transformedRect.Intersect(imageRect);
           InvalidateRect(aData->mRect);
 
           GP("TransformChange: %s %d %d %d %d\n", aItem->Name(),
                  aData->mRect.x, aData->mRect.y, aData->mRect.XMost(), aData->mRect.YMost());
         } else if (IsContainerLayerItem(aItem)) {
           UniquePtr<nsDisplayItemGeometry> geometry(aItem->AllocateGeometry(aBuilder));
           // we need to catch bounds changes of containers so that we continue to have the correct bounds rects in the recording
           if (UpdateContainerLayerPropertiesAndDetectChange(aItem, aData, *geometry)) {
             combined = clip.ApplyNonRoundedIntersection(geometry->ComputeInvalidationRegion());
             aData->mGeometry = std::move(geometry);
             IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mLayerBounds.TopLeft());
-            InvalidateRect(aData->mRect.Intersect(mImageBounds));
-            aData->mRect = transformedRect.Intersect(mImageBounds);
+            InvalidateRect(aData->mRect.Intersect(imageRect));
+            aData->mRect = transformedRect.Intersect(imageRect);
             InvalidateRect(aData->mRect);
             GP("UpdateContainerLayerPropertiesAndDetectChange change\n");
           } else {
             // XXX: this code can eventually be deleted/made debug only
             combined = clip.ApplyNonRoundedIntersection(geometry->ComputeInvalidationRegion());
+            IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mLayerBounds.TopLeft());
+            auto rect = transformedRect.Intersect(imageRect);
             GP("Layer NoChange: %s %d %d %d %d\n", aItem->Name(),
                    aData->mRect.x, aData->mRect.y, aData->mRect.XMost(), aData->mRect.YMost());
+            MOZ_RELEASE_ASSERT(rect.IsEqualEdges(aData->mRect));
           }
         } else {
           // XXX: this code can eventually be deleted/made debug only
           UniquePtr<nsDisplayItemGeometry> geometry(aItem->AllocateGeometry(aBuilder));
           combined = clip.ApplyNonRoundedIntersection(geometry->ComputeInvalidationRegion());
+          IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mLayerBounds.TopLeft());
+          auto rect = transformedRect.Intersect(imageRect);
           GP("NoChange: %s %d %d %d %d\n", aItem->Name(),
                  aData->mRect.x, aData->mRect.y, aData->mRect.XMost(), aData->mRect.YMost());
+          MOZ_RELEASE_ASSERT(rect.IsEqualEdges(aData->mRect));
         }
       }
     }
     aData->mClip = clip;
     aData->mMatrix = aMatrix;
     aData->mGroupOffset = mLayerBounds.TopLeft();
-    aData->mImageRect = mImageBounds;
+    aData->mImageRect = imageRect;
     GP("post mInvalidRect: %d %d %d %d\n", mInvalidRect.x, mInvalidRect.y, mInvalidRect.width, mInvalidRect.height);
   }
 
   void EndGroup(WebRenderLayerManager* aWrManager,
                 nsDisplayListBuilder* aDisplayListBuilder,
                 wr::DisplayListBuilder& aBuilder,
                 wr::IpcResourceUpdateQueue& aResources,
                 Grouper* aGrouper,
@@ -1053,17 +1060,16 @@ Grouper::ConstructGroups(nsDisplayListBu
         // The group changed size
         GP("Inner group size change\n");
         groupData->mFollowingGroup.ClearItems();
         groupData->mFollowingGroup.ClearImageKey(aCommandBuilder->mManager);
       }
       groupData->mFollowingGroup.mGroupBounds = currentGroup->mGroupBounds;
       groupData->mFollowingGroup.mAppUnitsPerDevPixel = currentGroup->mAppUnitsPerDevPixel;
       groupData->mFollowingGroup.mLayerBounds = currentGroup->mLayerBounds;
-      groupData->mFollowingGroup.mImageBounds = currentGroup->mImageBounds;
       groupData->mFollowingGroup.mScale = currentGroup->mScale;
       groupData->mFollowingGroup.mResidualOffset = currentGroup->mResidualOffset;
       groupData->mFollowingGroup.mPaintRect = currentGroup->mPaintRect;
 
       currentGroup = &groupData->mFollowingGroup;
 
       startOfCurrentGroup = item->GetAbove();
     } else { // inactive item
@@ -1108,46 +1114,32 @@ Grouper::ConstructItemInsideInactive(Web
   nsDisplayList* children = aItem->GetChildren();
   BlobItemData* data = GetBlobItemDataForGroup(aItem, aGroup);
 
   /* mInvalid unfortunately persists across paints. Clear it so that if we don't
    * set it to 'true' we ensure that we're not using the value from the last
    * time that we painted */
   data->mInvalid = false;
 
-  // we compute the geometry change here because we have the transform around still
-  aGroup->ComputeGeometryChange(aItem, data, mTransform, mDisplayListBuilder);
-  
-  // Temporarily restrict the image bounds to the bounds of the container so that
-  // clipped children within the container know about the clip.
-  IntRect oldImageBounds = aGroup->mImageBounds;
-  aGroup->mImageBounds = aGroup->mImageBounds.Intersect(data->mRect);
-
   if (aItem->GetType() == DisplayItemType::TYPE_FILTER) {
     gfx::Size scale(1, 1);
     // If ComputeDifferences finds any change, we invalidate the entire container item.
     // This is needed because blob merging requires the entire item to be within the invalid region.
-    if (BuildLayer(aItem, data, mDisplayListBuilder, scale)) {
-      data->mInvalid = true;
-      aGroup->InvalidateRect(data->mRect);
-    }
+    data->mInvalid = BuildLayer(aItem, data, mDisplayListBuilder, scale);
   } else if (aItem->GetType() == DisplayItemType::TYPE_TRANSFORM) {
     nsDisplayTransform* transformItem = static_cast<nsDisplayTransform*>(aItem);
     const Matrix4x4Flagged& t = transformItem->GetTransform();
     Matrix t2d;
     bool is2D = t.Is2D(&t2d);
     if (!is2D) {
       // We'll use BasicLayerManager to handle 3d transforms.
       gfx::Size scale(1, 1);
       // If ComputeDifferences finds any change, we invalidate the entire container item.
       // This is needed because blob merging requires the entire item to be within the invalid region.
-      if (BuildLayer(aItem, data, mDisplayListBuilder, scale)) {
-        data->mInvalid = true;
-        aGroup->InvalidateRect(data->mRect);
-      }
+      data->mInvalid = BuildLayer(aItem, data, mDisplayListBuilder, scale);
     } else {
       Matrix m = mTransform;
 
       GP("t2d: %f %f\n", t2d._31, t2d._32);
       mTransform.PreMultiply(t2d);
       GP("mTransform: %f %f\n", mTransform._31, mTransform._32);
       ConstructGroupInsideInactive(aCommandBuilder, aBuilder, aResources, aGroup, children, aSc);
 
@@ -1155,17 +1147,18 @@ Grouper::ConstructItemInsideInactive(Web
     }
   } else if (children) {
     sIndent++;
     ConstructGroupInsideInactive(aCommandBuilder, aBuilder, aResources, aGroup, children, aSc);
     sIndent--;
   }
 
   GP("Including %s of %d\n", aItem->Name(), aGroup->mDisplayItems.Count());
-  aGroup->mImageBounds = oldImageBounds;
+
+  aGroup->ComputeGeometryChange(aItem, data, mTransform, mDisplayListBuilder); // we compute the geometry change here because we have the transform around still
 }
 
 /* This is just a copy of nsRect::ScaleToOutsidePixels with an offset added in.
  * The offset is applied just before the rounding. It's in the scaled space. */
 static mozilla::gfx::IntRect
 ScaleToOutsidePixelsOffset(nsRect aRect, float aXScale, float aYScale,
                            nscoord aAppUnitsPerPixel, LayerPoint aOffset)
 {
@@ -1250,17 +1243,16 @@ WebRenderCommandBuilder::DoGroupingForDi
   group.mResidualOffset = residualOffset;
   group.mGroupBounds = groupBounds;
   group.mAppUnitsPerDevPixel = appUnitsPerDevPixel;
   group.mLayerBounds = LayerIntRect::FromUnknownRect(ScaleToOutsidePixelsOffset(group.mGroupBounds,
                                                                                 scale.width,
                                                                                 scale.height,
                                                                                 group.mAppUnitsPerDevPixel,
                                                                                 residualOffset));
-  group.mImageBounds = IntRect(0, 0, group.mLayerBounds.width, group.mLayerBounds.height);
   group.mPaintRect = LayerIntRect::FromUnknownRect(
                        ScaleToOutsidePixelsOffset(aWrappingItem->GetPaintRect(),
                                                   scale.width,
                                                   scale.height,
                                                   group.mAppUnitsPerDevPixel,
                                                   residualOffset))
                        .Intersect(group.mLayerBounds);
   // XXX: Make the paint rect relative to the layer bounds. After we include
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -1393,17 +1393,17 @@ pub extern "C" fn wr_resource_updates_ad
     image_key: WrImageKey,
     descriptor: &WrImageDescriptor,
     bytes: &mut WrVecU8,
 ) {
     txn.add_image(
         image_key,
         descriptor.into(),
         ImageData::new_blob_image(bytes.flush_into_vec()),
-        if descriptor.format == ImageFormat::BGRA8 { Some(256) } else { None }
+        None
     );
 }
 
 #[no_mangle]
 pub extern "C" fn wr_resource_updates_add_external_image(
     txn: &mut Transaction,
     image_key: WrImageKey,
     descriptor: &WrImageDescriptor,
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -319,32 +319,32 @@ random-if(gtkWidget) == objectBoundingBo
 
 == opacity-and-gradient-01.svg pass.svg
 skip-if(d2d) fuzzy-if(cocoaWidget,0-1,0-99974) fuzzy-if(skiaContent,0-1,0-200000) == opacity-and-gradient-02.svg opacity-and-gradient-02-ref.svg
 == opacity-and-pattern-01.svg pass.svg
 fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||skiaContent,0-1,0-10000) == opacity-and-transform-01.svg opacity-and-transform-01-ref.svg
 
 fuzzy-if(Android,0-8,0-200) == outer-svg-border-and-padding-01.svg outer-svg-border-and-padding-01-ref.svg
 
-fuzzy-if(skiaContent,0-7,0-175) fuzzy-if(webrender,54-54,124-124) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == outline.html outline-ref.html # Bug 1392106
+fuzzy-if(skiaContent,0-7,0-175) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == outline.html outline-ref.html # Bug 1392106
 
 == overflow-on-outer-svg-01.svg overflow-on-outer-svg-01-ref.svg
 == overflow-on-outer-svg-02a.xhtml overflow-on-outer-svg-02-ref.xhtml
 == overflow-on-outer-svg-02b.xhtml overflow-on-outer-svg-02-ref.xhtml
 == overflow-on-outer-svg-02c.xhtml overflow-on-outer-svg-02-ref.xhtml
 == overflow-on-outer-svg-02d.xhtml overflow-on-outer-svg-02-ref.xhtml
 == overflow-on-outer-svg-03a.xhtml overflow-on-outer-svg-03-ref.xhtml
 == overflow-on-outer-svg-03b.xhtml overflow-on-outer-svg-03-ref.xhtml
 
 == paint-on-maskLayer-1a.html paint-on-maskLayer-1-ref.html
 == paint-on-maskLayer-1b.html paint-on-maskLayer-1-ref.html
 == paint-on-maskLayer-1c.html paint-on-maskLayer-1-ref.html
 fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-15,0-5) == paint-order-01.svg paint-order-01-ref.svg
 == paint-order-02.svg paint-order-02-ref.svg
-fuzzy-if(webrender,72-72,96-143) == paint-order-03.svg paint-order-03-ref.svg
+== paint-order-03.svg paint-order-03-ref.svg
 
 #fuzzy(0-23,0-60) fails-if(d2d) == path-01.svg path-01-ref.svg
 == path-02.svg pass.svg
 == path-04.svg pass.svg
 == path-05.svg pass.svg
 fuzzy-if(skiaContent,0-1,0-400) == path-06.svg path-06-ref.svg
 == path-07.svg path-07-ref.svg
 == path-08.svg pass.svg
--- a/layout/reftests/text-stroke/reftest.list
+++ b/layout/reftests/text-stroke/reftest.list
@@ -1,10 +1,10 @@
 # basic tests for webkit-text-stroke
 # fuzzy is needed here for platform dependent backends
 default-preferences pref(layout.css.prefixes.webkit,true)
 
-fuzzy-if(gtkWidget,0-255,0-20) fuzzy-if(winWidget,0-20,0-10) fails-if(skiaContent&&(gtkWidget||winWidget)) fuzzy-if(cocoaWidget&&webrender,48-48,44-44) == webkit-text-stroke-property-001.html webkit-text-stroke-property-001-ref.html
-fuzzy-if(gtkWidget,0-255,0-20) fuzzy-if(winWidget,0-20,0-10) fails-if(skiaContent&&!webrender&&gtkWidget) fuzzy-if(webrender,3-4,4-24) == webkit-text-stroke-property-002.html webkit-text-stroke-property-002-ref.html
-fuzzy-if(gtkWidget,0-255,0-20) fuzzy-if(winWidget,0-20,0-10) fuzzy-if(webrender,32-48,26-26) fails-if(skiaContent&&gtkWidget) == webkit-text-stroke-property-003.html webkit-text-stroke-property-003-ref.html
-fuzzy-if(gtkWidget,0-255,0-20) fuzzy-if(winWidget,0-20,0-10) fuzzy-if(webrender,48-64,21-33) fails-if(skiaContent&&gtkWidget) == webkit-text-stroke-property-004.html webkit-text-stroke-property-004-ref.html
-fuzzy-if(gtkWidget,0-255,0-20) fuzzy-if(winWidget,0-20,0-10) fails-if(skiaContent&&(gtkWidget||winWidget)) fuzzy-if(cocoaWidget&&webrender,48-48,44-44) == webkit-text-stroke-property-005.html webkit-text-stroke-property-005-ref.html
+fuzzy-if(gtkWidget,0-255,0-20) fuzzy-if(winWidget,0-20,0-10) fails-if(skiaContent&&(gtkWidget||winWidget)) == webkit-text-stroke-property-001.html webkit-text-stroke-property-001-ref.html
+fuzzy-if(gtkWidget,0-255,0-20) fuzzy-if(winWidget,0-20,0-10) fails-if(skiaContent&&!webrender&&gtkWidget) == webkit-text-stroke-property-002.html webkit-text-stroke-property-002-ref.html
+fuzzy-if(gtkWidget,0-255,0-20) fuzzy-if(winWidget,0-20,0-10) fails-if(skiaContent&&gtkWidget) == webkit-text-stroke-property-003.html webkit-text-stroke-property-003-ref.html
+fuzzy-if(gtkWidget,0-255,0-20) fuzzy-if(winWidget,0-20,0-10) fails-if(skiaContent&&gtkWidget) == webkit-text-stroke-property-004.html webkit-text-stroke-property-004-ref.html
+fuzzy-if(gtkWidget,0-255,0-20) fuzzy-if(winWidget,0-20,0-10) fails-if(skiaContent&&(gtkWidget||winWidget)) == webkit-text-stroke-property-005.html webkit-text-stroke-property-005-ref.html
 fuzzy-if(gtkWidget,0-255,0-392) fuzzy-if(winWidget&&!d2d,0-48,0-372) fuzzy-if(winWidget&&d2d,0-71,0-10) == webkit-text-stroke-property-006.html webkit-text-stroke-property-006-ref.html