+
diff --git a/gfx/2d/2D.h b/gfx/2d/2D.h
index a8aa70b692..6a3f468f9e 100644
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -341,6 +341,57 @@ class SourceSurface : public external::AtomicRefCounted
{
virtual IntRect GetRect() const { return IntRect(IntPoint(0, 0), GetSize()); }
virtual SurfaceFormat GetFormat() const = 0;
+ /**
+ * Structure containing memory size information for the surface.
+ */
+ struct SizeOfInfo {
+ SizeOfInfo()
+ : mHeapBytes(0),
+ mNonHeapBytes(0),
+ mUnknownBytes(0),
+ mExternalHandles(0),
+#ifdef MOZ_BUILD_WEBRENDER
+ mExternalId(0),
+#endif
+ mTypes(0) {}
+
+ void Accumulate(const SizeOfInfo& aOther) {
+ mHeapBytes += aOther.mHeapBytes;
+ mNonHeapBytes += aOther.mNonHeapBytes;
+ mUnknownBytes += aOther.mUnknownBytes;
+ mExternalHandles += aOther.mExternalHandles;
+#ifdef MOZ_BUILD_WEBRENDER
+ if (aOther.mExternalId) {
+ mExternalId = aOther.mExternalId;
+ }
+#endif
+ mTypes |= aOther.mTypes;
+ }
+
+ void AddType(SurfaceType aType) { mTypes |= 1 << uint32_t(aType); }
+
+ size_t mHeapBytes; // Bytes allocated on the heap.
+ size_t mNonHeapBytes; // Bytes allocated off the heap.
+ size_t mUnknownBytes; // Bytes allocated to either, but unknown.
+ size_t mExternalHandles; // Open handles for the surface.
+#ifdef MOZ_BUILD_WEBRENDER
+ uint64_t mExternalId; // External ID for WebRender, if available.
+#endif
+ uint32_t mTypes; // Bit shifted values representing SurfaceType.
+ };
+
+ /**
+ * Get the size information of the underlying data buffer.
+ */
+ virtual void SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+ SizeOfInfo& aInfo) const {
+ // Default is to estimate the footprint based on its size/format.
+ auto size = GetSize();
+ auto format = GetFormat();
+ aInfo.AddType(GetType());
+ aInfo.mUnknownBytes = size.width * size.height * BytesPerPixel(format);
+ }
+
/** This returns false if some event has made this source surface invalid for
* usage with current DrawTargets. For example in the case of Direct2D this
* could return false if we have switched devices since this surface was
@@ -363,9 +414,15 @@ class SourceSurface : public external::AtomicRefCounted {
* DataSourceSurface and if GetDataSurface will return the same object.
*/
bool IsDataSourceSurface() const {
- SurfaceType type = GetType();
- return type == SurfaceType::DATA || type == SurfaceType::DATA_SHARED ||
- type == SurfaceType::DATA_RECYCLING_SHARED;
+ switch (GetType()) {
+ case SurfaceType::DATA:
+ case SurfaceType::DATA_SHARED:
+ case SurfaceType::DATA_RECYCLING_SHARED:
+ case SurfaceType::DATA_ALIGNED:
+ return true;
+ default:
+ return false;
+ }
}
/**
@@ -467,6 +524,11 @@ class DataSourceSurface : public SourceSurface {
return &mMap;
}
+ const DataSourceSurface* GetSurface() const {
+ MOZ_ASSERT(mIsMapped);
+ return mSurface;
+ }
+
bool IsMapped() const { return mIsMapped; }
private:
@@ -531,20 +593,6 @@ class DataSourceSurface : public SourceSurface {
*/
already_AddRefed GetDataSurface() override;
- /**
- * Add the size of the underlying data buffer to the aggregate.
- */
- virtual void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
- size_t& aHeapSizeOut,
- size_t& aNonHeapSizeOut,
- size_t& aExtHandlesOut
-#ifdef MOZ_BUILD_WEBRENDER
- ,
- uint64_t& aExtIdOut
-#endif
- ) const {
- }
-
/**
* Returns whether or not the data was allocated on the heap. This should
* be used to determine if the memory needs to be cleared to 0.
diff --git a/gfx/2d/DrawEventRecorder.cpp b/gfx/2d/DrawEventRecorder.cpp
index 10a3aaa4d8..f8896a3aa3 100644
--- a/gfx/2d/DrawEventRecorder.cpp
+++ b/gfx/2d/DrawEventRecorder.cpp
@@ -41,16 +41,12 @@ void DrawEventRecorderPrivate::StoreSourceSurfaceRecording(
}
void DrawEventRecorderFile::RecordEvent(const RecordedEvent& aEvent) {
- WriteElement(mOutputStream, aEvent.mType);
-
aEvent.RecordToStream(mOutputStream);
Flush();
}
void DrawEventRecorderMemory::RecordEvent(const RecordedEvent& aEvent) {
- WriteElement(mOutputStream, aEvent.mType);
-
aEvent.RecordToStream(mOutputStream);
}
diff --git a/gfx/2d/Logging.h b/gfx/2d/Logging.h
index fdec305998..9af75cf1c1 100644
--- a/gfx/2d/Logging.h
+++ b/gfx/2d/Logging.h
@@ -680,6 +680,12 @@ class Log final {
case SurfaceType::DATA_SHARED:
mMessage << "SurfaceType::DATA_SHARED";
break;
+ case SurfaceType::DATA_RECYCLING_SHARED:
+ mMessage << "SurfaceType::DATA_RECYCLING_SHARED";
+ break;
+ case SurfaceType::DATA_ALIGNED:
+ mMessage << "SurfaceType::DATA_ALIGNED";
+ break;
default:
mMessage << "Invalid SurfaceType (" << (int)aType << ")";
break;
diff --git a/gfx/2d/RecordedEventImpl.h b/gfx/2d/RecordedEventImpl.h
index cc13d4c779..664a658db8 100644
--- a/gfx/2d/RecordedEventImpl.h
+++ b/gfx/2d/RecordedEventImpl.h
@@ -24,16 +24,22 @@ class RecordedEventDerived : public RecordedEvent {
public:
void RecordToStream(std::ostream& aStream) const override {
+ WriteElement(aStream, this->mType);
static_cast(this)->Record(aStream);
}
void RecordToStream(EventStream& aStream) const override {
+ WriteElement(aStream, this->mType);
static_cast(this)->Record(aStream);
}
void RecordToStream(MemStream& aStream) const override {
SizeCollector size;
+ WriteElement(size, this->mType);
static_cast(this)->Record(size);
+
aStream.Resize(aStream.mLength + size.mTotalSize);
+
MemWriter writer(aStream.mData + aStream.mLength - size.mTotalSize);
+ WriteElement(writer, this->mType);
static_cast(this)->Record(writer);
}
};
diff --git a/gfx/2d/SourceSurfaceCapture.cpp b/gfx/2d/SourceSurfaceCapture.cpp
index 95fb63c4fd..3810091391 100644
--- a/gfx/2d/SourceSurfaceCapture.cpp
+++ b/gfx/2d/SourceSurfaceCapture.cpp
@@ -62,11 +62,42 @@ SourceSurfaceCapture::SourceSurfaceCapture(DrawTargetCaptureImpl* aOwner,
SourceSurfaceCapture::~SourceSurfaceCapture() {}
+void SourceSurfaceCapture::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+ SizeOfInfo& aInfo) const {
+ MutexAutoLock lock(mLock);
+ aInfo.AddType(SurfaceType::CAPTURE);
+ if (mSurfToOptimize) {
+ mSurfToOptimize->SizeOfExcludingThis(aMallocSizeOf, aInfo);
+ return;
+ }
+ if (mResolved) {
+ mResolved->SizeOfExcludingThis(aMallocSizeOf, aInfo);
+ return;
+ }
+ if (mHasCommandList) {
+ aInfo.mHeapBytes += mCommands.BufferCapacity();
+ return;
+ }
+}
+
bool SourceSurfaceCapture::IsValid() const {
// We must either be able to source a command list, or we must have a cached
// and rasterized surface.
MutexAutoLock lock(mLock);
- return (mOwner || mHasCommandList || mSurfToOptimize) || mResolved;
+
+ if (mSurfToOptimize) {
+ // We were given a surface, but we haven't tried to optimize it yet
+ // with the reference draw target.
+ return mSurfToOptimize->IsValid();
+ }
+ if (mResolved) {
+ // We were given a surface, and we already optimized it with the
+ // reference draw target.
+ return mResolved->IsValid();
+ }
+
+ // We have no underlying surface, so it must be a set of drawing commands.
+ return mOwner || mHasCommandList;
}
RefPtr SourceSurfaceCapture::Resolve(BackendType aBackendType) {
diff --git a/gfx/2d/SourceSurfaceCapture.h b/gfx/2d/SourceSurfaceCapture.h
index 075ec09355..e8aff2371b 100644
--- a/gfx/2d/SourceSurfaceCapture.h
+++ b/gfx/2d/SourceSurfaceCapture.h
@@ -31,6 +31,9 @@ class SourceSurfaceCapture : public SourceSurface {
IntSize GetSize() const override { return mSize; }
SurfaceFormat GetFormat() const override { return mFormat; }
+ void SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+ SizeOfInfo& aInfo) const override;
+
bool IsValid() const override;
already_AddRefed GetDataSurface() override;
diff --git a/gfx/2d/SourceSurfaceRawData.cpp b/gfx/2d/SourceSurfaceRawData.cpp
index 5046b2ae64..6cc503b0f4 100644
--- a/gfx/2d/SourceSurfaceRawData.cpp
+++ b/gfx/2d/SourceSurfaceRawData.cpp
@@ -40,6 +40,16 @@ void SourceSurfaceRawData::GuaranteePersistance() {
mOwnData = true;
}
+void SourceSurfaceRawData::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+ SizeOfInfo& aInfo) const {
+ aInfo.AddType(SurfaceType::DATA);
+ if (mDeallocator) {
+ aInfo.mUnknownBytes = mStride * mSize.height;
+ } else if (mOwnData) {
+ aInfo.mHeapBytes = mStride * mSize.height;
+ }
+}
+
bool SourceSurfaceAlignedRawData::Init(const IntSize& aSize,
SurfaceFormat aFormat, bool aClearMem,
uint8_t aClearValue, int32_t aStride) {
@@ -69,15 +79,10 @@ bool SourceSurfaceAlignedRawData::Init(const IntSize& aSize,
return mArray != nullptr;
}
-void SourceSurfaceAlignedRawData::AddSizeOfExcludingThis(
- MallocSizeOf aMallocSizeOf, size_t& aHeapSizeOut, size_t& aNonHeapSizeOut,
- size_t& aExtHandlesOut
-#ifdef MOZ_BUILD_WEBRENDER
- ,
- uint64_t& aExtIdOut
-#endif
-) const {
- aHeapSizeOut += mArray.HeapSizeOfExcludingThis(aMallocSizeOf);
+void SourceSurfaceAlignedRawData::SizeOfExcludingThis(
+ MallocSizeOf aMallocSizeOf, SizeOfInfo& aInfo) const {
+ aInfo.AddType(SurfaceType::DATA_ALIGNED);
+ aInfo.mHeapBytes = mArray.HeapSizeOfExcludingThis(aMallocSizeOf);
}
} // namespace gfx
diff --git a/gfx/2d/SourceSurfaceRawData.h b/gfx/2d/SourceSurfaceRawData.h
index d985afd215..aa57a57ac3 100644
--- a/gfx/2d/SourceSurfaceRawData.h
+++ b/gfx/2d/SourceSurfaceRawData.h
@@ -12,6 +12,37 @@
namespace mozilla {
namespace gfx {
+class SourceSurfaceMappedData final : public DataSourceSurface {
+ public:
+ MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceMappedData, final)
+
+ SourceSurfaceMappedData(ScopedMap&& aMap, const IntSize& aSize,
+ SurfaceFormat aFormat)
+ : mMap(std::move(aMap)), mSize(aSize), mFormat(aFormat) {}
+
+ ~SourceSurfaceMappedData() final {}
+
+ uint8_t* GetData() final { return mMap.GetData(); }
+ int32_t Stride() final { return mMap.GetStride(); }
+
+ SurfaceType GetType() const final { return SurfaceType::DATA; }
+ IntSize GetSize() const final { return mSize; }
+ SurfaceFormat GetFormat() const final { return mFormat; }
+
+ void SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+ SizeOfInfo& aInfo) const override {
+ aInfo.AddType(SurfaceType::DATA);
+ mMap.GetSurface()->SizeOfExcludingThis(aMallocSizeOf, aInfo);
+ }
+
+ void GuaranteePersistance() final {}
+
+ private:
+ ScopedMap mMap;
+ IntSize mSize;
+ SurfaceFormat mFormat;
+};
+
class SourceSurfaceRawData : public DataSourceSurface {
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceRawData, override)
@@ -40,6 +71,9 @@ class SourceSurfaceRawData : public DataSourceSurface {
virtual IntSize GetSize() const override { return mSize; }
virtual SurfaceFormat GetFormat() const override { return mFormat; }
+ void SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+ SizeOfInfo& aInfo) const override;
+
virtual void GuaranteePersistance() override;
private:
@@ -68,25 +102,20 @@ class SourceSurfaceAlignedRawData : public DataSourceSurface {
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceAlignedRawData,
override)
SourceSurfaceAlignedRawData() : mStride(0), mFormat(SurfaceFormat::UNKNOWN) {}
- ~SourceSurfaceAlignedRawData() {}
+ ~SourceSurfaceAlignedRawData() override {}
bool Init(const IntSize& aSize, SurfaceFormat aFormat, bool aClearMem,
uint8_t aClearValue, int32_t aStride = 0);
- virtual uint8_t* GetData() override { return mArray; }
- virtual int32_t Stride() override { return mStride; }
+ uint8_t* GetData() override { return mArray; }
+ 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; }
+ SurfaceType GetType() const override { return SurfaceType::DATA_ALIGNED; }
+ IntSize GetSize() const override { return mSize; }
+ SurfaceFormat GetFormat() const override { return mFormat; }
- void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, size_t& aHeapSizeOut,
- size_t& aNonHeapSizeOut, size_t& aExtHandlesOut
-#ifdef MOZ_BUILD_WEBRENDER
- ,
- uint64_t& aExtIdOut
-#endif
- ) const override;
+ void SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+ SizeOfInfo& aInfo) const override;
private:
friend class Factory;
diff --git a/gfx/2d/Swizzle.cpp b/gfx/2d/Swizzle.cpp
index 3d1afcb8c0..850f8bcceb 100644
--- a/gfx/2d/Swizzle.cpp
+++ b/gfx/2d/Swizzle.cpp
@@ -39,6 +39,10 @@ namespace gfx {
#define FORMAT_CASE(aSrcFormat, aDstFormat, ...) \
FORMAT_CASE_EXPR(aSrcFormat, aDstFormat, FORMAT_CASE_CALL(__VA_ARGS__))
+#define FORMAT_CASE_ROW(aSrcFormat, aDstFormat, ...) \
+ case FORMAT_KEY(aSrcFormat, aDstFormat): \
+ return &__VA_ARGS__;
+
/**
* Constexpr functions for analyzing format attributes in templates.
*/
@@ -112,6 +116,15 @@ void Premultiply_SSE2(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize);
Premultiply_SSE2)
+template
+void PremultiplyRow_SSE2(const uint8_t*, uint8_t*, int32_t);
+
+# define PREMULTIPLY_ROW_SSE2(aSrcFormat, aDstFormat) \
+ FORMAT_CASE_ROW( \
+ aSrcFormat, aDstFormat, \
+ PremultiplyRow_SSE2)
+
template
void Unpremultiply_SSE2(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize);
@@ -127,6 +140,32 @@ void Swizzle_SSE2(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize);
Swizzle_SSE2)
+template
+void SwizzleRow_SSE2(const uint8_t*, uint8_t*, int32_t);
+
+# define SWIZZLE_ROW_SSE2(aSrcFormat, aDstFormat) \
+ FORMAT_CASE_ROW( \
+ aSrcFormat, aDstFormat, \
+ SwizzleRow_SSE2)
+
+template
+void UnpackRowRGB24_SSSE3(const uint8_t*, uint8_t*, int32_t);
+
+# define UNPACK_ROW_RGB_SSSE3(aDstFormat) \
+ FORMAT_CASE_ROW( \
+ SurfaceFormat::R8G8B8, aDstFormat, \
+ UnpackRowRGB24_SSSE3)
+
+/*** ne nado
+template
+void UnpackRowRGB24_AVX2(const uint8_t*, uint8_t*, int32_t);
+
+# define UNPACK_ROW_RGB_AVX2(aDstFormat) \
+ FORMAT_CASE_ROW( \
+ SurfaceFormat::R8G8B8, aDstFormat, \
+ UnpackRowRGB24_AVX2)
+*/
#endif
#ifdef USE_NEON
@@ -142,6 +181,15 @@ void Premultiply_NEON(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize);
Premultiply_NEON)
+template
+void PremultiplyRow_NEON(const uint8_t*, uint8_t*, int32_t);
+
+# define PREMULTIPLY_ROW_NEON(aSrcFormat, aDstFormat) \
+ FORMAT_CASE_ROW( \
+ aSrcFormat, aDstFormat, \
+ PremultiplyRow_NEON)
+
template
void Unpremultiply_NEON(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize);
@@ -157,6 +205,14 @@ void Swizzle_NEON(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize);
Swizzle_NEON)
+template
+void SwizzleRow_NEON(const uint8_t*, uint8_t*, int32_t);
+
+# define SWIZZLE_ROW_NEON(aSrcFormat, aDstFormat) \
+ FORMAT_CASE_ROW( \
+ aSrcFormat, aDstFormat, \
+ SwizzleRow_NEON)
#endif
/**
@@ -169,51 +225,65 @@ void Swizzle_NEON(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize);
// 2-component vectors. Otherwise, an approximation if divide-by-255 is used
// which is faster than an actual division. These optimizations are also used
// for the SSE2 and NEON implementations.
+template
+static void PremultiplyChunkFallback(const uint8_t*& aSrc, uint8_t*& aDst,
+ int32_t aLength) {
+ const uint8_t* end = aSrc + 4 * aLength;
+ do {
+ // Load and process 1 entire pixel at a time.
+ uint32_t color = *reinterpret_cast(aSrc);
+
+ uint32_t a = aSrcAShift ? color >> aSrcAShift : color & 0xFF;
+
+ // Isolate the R and B components.
+ uint32_t rb = (color >> aSrcRGBShift) & 0x00FF00FF;
+ // Swap the order of R and B if necessary.
+ if (aSwapRB) {
+ rb = (rb >> 16) | (rb << 16);
+ }
+ // Approximate the multiply by alpha and divide by 255 which is
+ // essentially:
+ // c = c*a + 255; c = (c + (c >> 8)) >> 8;
+ // However, we omit the final >> 8 to fold it with the final shift into
+ // place depending on desired output format.
+ rb = rb * a + 0x00FF00FF;
+ rb = (rb + ((rb >> 8) & 0x00FF00FF)) & 0xFF00FF00;
+
+ // Use same approximation as above, but G is shifted 8 bits left.
+ // Alpha is left out and handled separately.
+ uint32_t g = color & (0xFF00 << aSrcRGBShift);
+ g = g * a + (0xFF00 << aSrcRGBShift);
+ g = (g + (g >> 8)) & (0xFF0000 << aSrcRGBShift);
+
+ // The above math leaves RGB shifted left by 8 bits.
+ // Shift them right if required for the output format.
+ // then combine them back together to produce output pixel.
+ // Add the alpha back on if the output format is not opaque.
+ *reinterpret_cast(aDst) =
+ (rb >> (8 - aDstRGBShift)) | (g >> (8 + aSrcRGBShift - aDstRGBShift)) |
+ (aOpaqueAlpha ? 0xFF << aDstAShift : a << aDstAShift);
+
+ aSrc += 4;
+ aDst += 4;
+ } while (aSrc < end);
+}
+
+template
+static void PremultiplyRowFallback(const uint8_t* aSrc, uint8_t* aDst,
+ int32_t aLength) {
+ PremultiplyChunkFallback(aSrc, aDst, aLength);
+}
+
template
static void PremultiplyFallback(const uint8_t* aSrc, int32_t aSrcGap,
uint8_t* aDst, int32_t aDstGap, IntSize aSize) {
for (int32_t height = aSize.height; height > 0; height--) {
- const uint8_t* end = aSrc + 4 * aSize.width;
- do {
- // Load and process 1 entire pixel at a time.
- uint32_t color = *reinterpret_cast(aSrc);
-
- uint32_t a = aSrcAShift ? color >> aSrcAShift : color & 0xFF;
-
- // Isolate the R and B components.
- uint32_t rb = (color >> aSrcRGBShift) & 0x00FF00FF;
- // Swap the order of R and B if necessary.
- if (aSwapRB) {
- rb = (rb >> 16) | (rb << 16);
- }
- // Approximate the multiply by alpha and divide by 255 which is
- // essentially:
- // c = c*a + 255; c = (c + (c >> 8)) >> 8;
- // However, we omit the final >> 8 to fold it with the final shift into
- // place depending on desired output format.
- rb = rb * a + 0x00FF00FF;
- rb = (rb + ((rb >> 8) & 0x00FF00FF)) & 0xFF00FF00;
-
- // Use same approximation as above, but G is shifted 8 bits left.
- // Alpha is left out and handled separately.
- uint32_t g = color & (0xFF00 << aSrcRGBShift);
- g = g * a + (0xFF00 << aSrcRGBShift);
- g = (g + (g >> 8)) & (0xFF0000 << aSrcRGBShift);
-
- // The above math leaves RGB shifted left by 8 bits.
- // Shift them right if required for the output format.
- // then combine them back together to produce output pixel.
- // Add the alpha back on if the output format is not opaque.
- *reinterpret_cast(aDst) =
- (rb >> (8 - aDstRGBShift)) |
- (g >> (8 + aSrcRGBShift - aDstRGBShift)) |
- (aOpaqueAlpha ? 0xFF << aDstAShift : a << aDstAShift);
-
- aSrc += 4;
- aDst += 4;
- } while (aSrc < end);
-
+ PremultiplyChunkFallback(aSrc, aDst, aSize.width);
aSrc += aSrcGap;
aDst += aDstGap;
}
@@ -235,6 +305,22 @@ static void PremultiplyFallback(const uint8_t* aSrc, int32_t aSrcGap,
PREMULTIPLY_FALLBACK_CASE(aSrcFormat, SurfaceFormat::A8R8G8B8) \
PREMULTIPLY_FALLBACK_CASE(aSrcFormat, SurfaceFormat::X8R8G8B8)
+#define PREMULTIPLY_ROW_FALLBACK_CASE(aSrcFormat, aDstFormat) \
+ FORMAT_CASE_ROW(aSrcFormat, aDstFormat, \
+ PremultiplyRowFallback< \
+ ShouldSwapRB(aSrcFormat, aDstFormat), \
+ ShouldForceOpaque(aSrcFormat, aDstFormat), \
+ RGBBitShift(aSrcFormat), AlphaBitShift(aSrcFormat), \
+ RGBBitShift(aDstFormat), AlphaBitShift(aDstFormat)>)
+
+#define PREMULTIPLY_ROW_FALLBACK(aSrcFormat) \
+ PREMULTIPLY_ROW_FALLBACK_CASE(aSrcFormat, SurfaceFormat::B8G8R8A8) \
+ PREMULTIPLY_ROW_FALLBACK_CASE(aSrcFormat, SurfaceFormat::B8G8R8X8) \
+ PREMULTIPLY_ROW_FALLBACK_CASE(aSrcFormat, SurfaceFormat::R8G8B8A8) \
+ PREMULTIPLY_ROW_FALLBACK_CASE(aSrcFormat, SurfaceFormat::R8G8B8X8) \
+ PREMULTIPLY_ROW_FALLBACK_CASE(aSrcFormat, SurfaceFormat::A8R8G8B8) \
+ PREMULTIPLY_ROW_FALLBACK_CASE(aSrcFormat, SurfaceFormat::X8R8G8B8)
+
// If rows are tightly packed, and the size of the total area will fit within
// the precision range of a single row, then process all the data as if it was
// a single row.
@@ -321,6 +407,50 @@ bool PremultiplyData(const uint8_t* aSrc, int32_t aSrcStride,
return false;
}
+SwizzleRowFn PremultiplyRow(SurfaceFormat aSrcFormat,
+ SurfaceFormat aDstFormat) {
+#ifdef USE_SSE2
+ if (mozilla::supports_sse2()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) {
+ PREMULTIPLY_ROW_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8A8)
+ PREMULTIPLY_ROW_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8X8)
+ PREMULTIPLY_ROW_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8)
+ PREMULTIPLY_ROW_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8)
+ PREMULTIPLY_ROW_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8A8)
+ PREMULTIPLY_ROW_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8X8)
+ PREMULTIPLY_ROW_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8)
+ PREMULTIPLY_ROW_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8)
+ default:
+ break;
+ }
+#endif
+
+#ifdef USE_NEON
+ if (mozilla::supports_neon()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) {
+ PREMULTIPLY_ROW_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8A8)
+ PREMULTIPLY_ROW_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8X8)
+ PREMULTIPLY_ROW_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8)
+ PREMULTIPLY_ROW_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8)
+ PREMULTIPLY_ROW_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8A8)
+ PREMULTIPLY_ROW_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8X8)
+ PREMULTIPLY_ROW_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8)
+ PREMULTIPLY_ROW_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8)
+ default:
+ break;
+ }
+#endif
+
+ switch (FORMAT_KEY(aSrcFormat, aDstFormat)) {
+ PREMULTIPLY_ROW_FALLBACK(SurfaceFormat::B8G8R8A8)
+ PREMULTIPLY_ROW_FALLBACK(SurfaceFormat::R8G8B8A8)
+ PREMULTIPLY_ROW_FALLBACK(SurfaceFormat::A8R8G8B8)
+ default:
+ break;
+ }
+
+ MOZ_ASSERT_UNREACHABLE("Unsupported premultiply formats");
+ return nullptr;
+}
+
/**
* Unpremultiplying
*/
@@ -455,39 +585,54 @@ bool UnpremultiplyData(const uint8_t* aSrc, int32_t aSrcStride,
// Fallback swizzle implementation that uses shifting and masking to reorder
// pixels.
+template
+static void SwizzleChunkFallback(const uint8_t*& aSrc, uint8_t*& aDst,
+ int32_t aLength) {
+ const uint8_t* end = aSrc + 4 * aLength;
+ do {
+ uint32_t rgba = *reinterpret_cast(aSrc);
+
+ if (aSwapRB) {
+ // Handle R and B swaps by exchanging words and masking.
+ uint32_t rb =
+ ((rgba << 16) | (rgba >> 16)) & (0x00FF00FF << aSrcRGBShift);
+ uint32_t ga = rgba & ((0xFF << aSrcAShift) | (0xFF00 << aSrcRGBShift));
+ rgba = rb | ga;
+ }
+
+ // If src and dst shifts differ, rotate left or right to move RGB into
+ // place, i.e. ARGB -> RGBA or ARGB -> RGBA.
+ if (aDstRGBShift > aSrcRGBShift) {
+ rgba = (rgba << 8) | (aOpaqueAlpha ? 0x000000FF : rgba >> 24);
+ } else if (aSrcRGBShift > aDstRGBShift) {
+ rgba = (rgba >> 8) | (aOpaqueAlpha ? 0xFF000000 : rgba << 24);
+ } else if (aOpaqueAlpha) {
+ rgba |= 0xFF << aDstAShift;
+ }
+
+ *reinterpret_cast(aDst) = rgba;
+
+ aSrc += 4;
+ aDst += 4;
+ } while (aSrc < end);
+}
+
+template
+static void SwizzleRowFallback(const uint8_t* aSrc, uint8_t* aDst,
+ int32_t aLength) {
+ SwizzleChunkFallback(aSrc, aDst, aLength);
+}
+
template
static void SwizzleFallback(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
int32_t aDstGap, IntSize aSize) {
for (int32_t height = aSize.height; height > 0; height--) {
- const uint8_t* end = aSrc + 4 * aSize.width;
- do {
- uint32_t rgba = *reinterpret_cast(aSrc);
-
- if (aSwapRB) {
- // Handle R and B swaps by exchanging words and masking.
- uint32_t rb =
- ((rgba << 16) | (rgba >> 16)) & (0x00FF00FF << aSrcRGBShift);
- uint32_t ga = rgba & ((0xFF << aSrcAShift) | (0xFF00 << aSrcRGBShift));
- rgba = rb | ga;
- }
-
- // If src and dst shifts differ, rotate left or right to move RGB into
- // place, i.e. ARGB -> RGBA or ARGB -> RGBA.
- if (aDstRGBShift > aSrcRGBShift) {
- rgba = (rgba << 8) | (aOpaqueAlpha ? 0x000000FF : rgba >> 24);
- } else if (aSrcRGBShift > aDstRGBShift) {
- rgba = (rgba >> 8) | (aOpaqueAlpha ? 0xFF000000 : rgba << 24);
- } else if (aOpaqueAlpha) {
- rgba |= 0xFF << aDstAShift;
- }
-
- *reinterpret_cast(aDst) = rgba;
-
- aSrc += 4;
- aDst += 4;
- } while (aSrc < end);
-
+ SwizzleChunkFallback(aSrc, aDst, aSize.width);
aSrc += aSrcGap;
aDst += aDstGap;
}
@@ -501,6 +646,14 @@ static void SwizzleFallback(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
RGBBitShift(aSrcFormat), AlphaBitShift(aSrcFormat), \
RGBBitShift(aDstFormat), AlphaBitShift(aDstFormat)>)
+#define SWIZZLE_ROW_FALLBACK(aSrcFormat, aDstFormat) \
+ FORMAT_CASE_ROW( \
+ aSrcFormat, aDstFormat, \
+ SwizzleRowFallback)
+
// Fast-path for matching formats.
static void SwizzleCopy(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
int32_t aDstGap, IntSize aSize, int32_t aBPP) {
@@ -515,26 +668,39 @@ static void SwizzleCopy(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
}
// Fast-path for conversions that swap all bytes.
+template
+static void SwizzleChunkSwap(const uint8_t*& aSrc, uint8_t*& aDst,
+ int32_t aLength) {
+ const uint8_t* end = aSrc + 4 * aLength;
+ do {
+ // Use an endian swap to move the bytes, i.e. BGRA -> ARGB.
+ uint32_t rgba = *reinterpret_cast(aSrc);
+#if MOZ_LITTLE_ENDIAN()
+ rgba = NativeEndian::swapToBigEndian(rgba);
+#else
+ rgba = NativeEndian::swapToLittleEndian(rgba);
+#endif
+ if (aOpaqueAlpha) {
+ rgba |= 0xFF << aDstAShift;
+ }
+ *reinterpret_cast(aDst) = rgba;
+ aSrc += 4;
+ aDst += 4;
+ } while (aSrc < end);
+}
+
+template
+static void SwizzleRowSwap(const uint8_t* aSrc, uint8_t* aDst,
+ int32_t aLength) {
+ SwizzleChunkSwap(aSrc, aDst, aLength);
+}
+
template
static void SwizzleSwap(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
int32_t aDstGap, IntSize aSize) {
for (int32_t height = aSize.height; height > 0; height--) {
- const uint8_t* end = aSrc + 4 * aSize.width;
- do {
- // Use an endian swap to move the bytes, i.e. BGRA -> ARGB.
- uint32_t rgba = *reinterpret_cast(aSrc);
-#if MOZ_LITTLE_ENDIAN()
- rgba = NativeEndian::swapToBigEndian(rgba);
-#else
- rgba = NativeEndian::swapToLittleEndian(rgba);
-#endif
- if (aOpaqueAlpha) {
- rgba |= 0xFF << aDstAShift;
- }
- *reinterpret_cast(aDst) = rgba;
- aSrc += 4;
- aDst += 4;
- } while (aSrc < end);
+ SwizzleChunkSwap(aSrc, aDst,
+ aSize.width);
aSrc += aSrcGap;
aDst += aDstGap;
}
@@ -546,34 +712,61 @@ static void SwizzleSwap(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
SwizzleSwap)
+#define SWIZZLE_ROW_SWAP(aSrcFormat, aDstFormat) \
+ FORMAT_CASE_ROW( \
+ aSrcFormat, aDstFormat, \
+ SwizzleRowSwap)
+
// Fast-path for conversions that force alpha to opaque.
+template
+static void SwizzleChunkOpaqueUpdate(uint8_t*& aBuffer, int32_t aLength) {
+ const uint8_t* end = aBuffer + 4 * aLength;
+ do {
+ uint32_t rgba = *reinterpret_cast(aBuffer);
+ // Just add on the alpha bits to the source.
+ rgba |= 0xFF << aDstAShift;
+ *reinterpret_cast(aBuffer) = rgba;
+ aBuffer += 4;
+ } while (aBuffer < end);
+}
+
+template
+static void SwizzleChunkOpaqueCopy(const uint8_t*& aSrc, uint8_t* aDst,
+ int32_t aLength) {
+ const uint8_t* end = aSrc + 4 * aLength;
+ do {
+ uint32_t rgba = *reinterpret_cast(aSrc);
+ // Just add on the alpha bits to the source.
+ rgba |= 0xFF << aDstAShift;
+ *reinterpret_cast(aDst) = rgba;
+ aSrc += 4;
+ aDst += 4;
+ } while (aSrc < end);
+}
+
+template
+static void SwizzleRowOpaque(const uint8_t* aSrc, uint8_t* aDst,
+ int32_t aLength) {
+ if (aSrc == aDst) {
+ SwizzleChunkOpaqueUpdate(aDst, aLength);
+ } else {
+ SwizzleChunkOpaqueCopy(aSrc, aDst, aLength);
+ }
+}
+
template
static void SwizzleOpaque(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
int32_t aDstGap, IntSize aSize) {
if (aSrc == aDst) {
// Modifying in-place, so just write out the alpha.
for (int32_t height = aSize.height; height > 0; height--) {
- const uint8_t* end = aDst + 4 * aSize.width;
- do {
- // ORing directly onto destination memory profiles faster than writing
- // individually to the alpha byte and also profiles equivalently to a
- // SSE2 implementation.
- *reinterpret_cast(aDst) |= 0xFF << aDstAShift;
- aDst += 4;
- } while (aDst < end);
+ SwizzleChunkOpaqueUpdate(aDst, aSize.width);
aDst += aDstGap;
}
} else {
for (int32_t height = aSize.height; height > 0; height--) {
- const uint8_t* end = aSrc + 4 * aSize.width;
- do {
- uint32_t rgba = *reinterpret_cast(aSrc);
- // Just add on the alpha bits to the source.
- rgba |= 0xFF << aDstAShift;
- *reinterpret_cast(aDst) = rgba;
- aSrc += 4;
- aDst += 4;
- } while (aSrc < end);
+ SwizzleChunkOpaqueCopy(aSrc, aDst, aSize.width);
aSrc += aSrcGap;
aDst += aDstGap;
}
@@ -583,6 +776,10 @@ static void SwizzleOpaque(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
#define SWIZZLE_OPAQUE(aSrcFormat, aDstFormat) \
FORMAT_CASE(aSrcFormat, aDstFormat, SwizzleOpaque)
+#define SWIZZLE_ROW_OPAQUE(aSrcFormat, aDstFormat) \
+ FORMAT_CASE_ROW(aSrcFormat, aDstFormat, \
+ SwizzleRowOpaque)
+
// Packing of 32-bit formats to RGB565.
template
static void PackToRGB565(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
@@ -676,6 +873,56 @@ static void PackToA8(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
PACK_ALPHA_CASE(SurfaceFormat::R8G8B8A8, aDstFormat, aPackFunc) \
PACK_ALPHA_CASE(SurfaceFormat::A8R8G8B8, aDstFormat, aPackFunc)
+template
+void UnpackRowRGB24(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength) {
+ // Because we are expanding, we can only process the data back to front in
+ // case we are performing this in place.
+ const uint8_t* src = aSrc + 3 * (aLength - 1);
+ uint32_t* dst = reinterpret_cast(aDst + 4 * aLength);
+ while (src >= aSrc) {
+ uint8_t r = src[aSwapRB ? 2 : 0];
+ uint8_t g = src[1];
+ uint8_t b = src[aSwapRB ? 0 : 2];
+#if MOZ_LITTLE_ENDIAN()
+ *--dst = 0xFF000000 | (b << 16) | (g << 8) | r;
+#else
+ *--dst = 0x000000FF | (b << 8) | (g << 16) | (r << 24);
+#endif
+ src -= 3;
+ }
+}
+
+// Force instantiation of swizzle variants here.
+template void UnpackRowRGB24(const uint8_t*, uint8_t*, int32_t);
+template void UnpackRowRGB24(const uint8_t*, uint8_t*, int32_t);
+
+#define UNPACK_ROW_RGB(aDstFormat) \
+ FORMAT_CASE_ROW( \
+ SurfaceFormat::R8G8B8, aDstFormat, \
+ UnpackRowRGB24)
+
+static void UnpackRowRGB24_To_ARGB(const uint8_t* aSrc, uint8_t* aDst,
+ int32_t aLength) {
+ // Because we are expanding, we can only process the data back to front in
+ // case we are performing this in place.
+ const uint8_t* src = aSrc + 3 * (aLength - 1);
+ uint32_t* dst = reinterpret_cast(aDst + 4 * aLength);
+ while (src >= aSrc) {
+ uint8_t r = src[0];
+ uint8_t g = src[1];
+ uint8_t b = src[2];
+#if MOZ_LITTLE_ENDIAN()
+ *--dst = 0x000000FF | (r << 8) | (g << 16) | (b << 24);
+#else
+ *--dst = 0xFF000000 | (r << 24) | (g << 16) | b;
+#endif
+ src -= 3;
+ }
+}
+
+#define UNPACK_ROW_RGB_TO_ARGB(aDstFormat) \
+ FORMAT_CASE_ROW(SurfaceFormat::R8G8B8, aDstFormat, UnpackRowRGB24_To_ARGB)
+
bool SwizzleData(const uint8_t* aSrc, int32_t aSrcStride,
SurfaceFormat aSrcFormat, uint8_t* aDst, int32_t aDstStride,
SurfaceFormat aDstFormat, const IntSize& aSize) {
@@ -778,5 +1025,105 @@ bool SwizzleData(const uint8_t* aSrc, int32_t aSrcStride,
return false;
}
+SwizzleRowFn SwizzleRow(SurfaceFormat aSrcFormat, SurfaceFormat aDstFormat) {
+#ifdef USE_SSE2
+/*** ne nado
+ if (mozilla::supports_avx2()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) {
+ UNPACK_ROW_RGB_AVX2(SurfaceFormat::R8G8B8X8)
+ UNPACK_ROW_RGB_AVX2(SurfaceFormat::R8G8B8A8)
+ UNPACK_ROW_RGB_AVX2(SurfaceFormat::B8G8R8X8)
+ UNPACK_ROW_RGB_AVX2(SurfaceFormat::B8G8R8A8)
+ default:
+ break;
+ }
+*/
+
+ if (mozilla::supports_ssse3()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) {
+ UNPACK_ROW_RGB_SSSE3(SurfaceFormat::R8G8B8X8)
+ UNPACK_ROW_RGB_SSSE3(SurfaceFormat::R8G8B8A8)
+ UNPACK_ROW_RGB_SSSE3(SurfaceFormat::B8G8R8X8)
+ UNPACK_ROW_RGB_SSSE3(SurfaceFormat::B8G8R8A8)
+ default:
+ break;
+ }
+
+ if (mozilla::supports_sse2()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) {
+ SWIZZLE_ROW_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8)
+ SWIZZLE_ROW_SSE2(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8X8)
+ SWIZZLE_ROW_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8)
+ SWIZZLE_ROW_SSE2(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8A8)
+ SWIZZLE_ROW_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8)
+ SWIZZLE_ROW_SSE2(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8X8)
+ SWIZZLE_ROW_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8)
+ SWIZZLE_ROW_SSE2(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8A8)
+ default:
+ break;
+ }
+#endif
+
+#ifdef USE_NEON
+ if (mozilla::supports_neon()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) {
+ SWIZZLE_ROW_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8)
+ SWIZZLE_ROW_NEON(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8X8)
+ SWIZZLE_ROW_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8)
+ SWIZZLE_ROW_NEON(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8A8)
+ SWIZZLE_ROW_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8)
+ SWIZZLE_ROW_NEON(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8X8)
+ SWIZZLE_ROW_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8)
+ SWIZZLE_ROW_NEON(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8A8)
+ default:
+ break;
+ }
+#endif
+
+ switch (FORMAT_KEY(aSrcFormat, aDstFormat)) {
+ SWIZZLE_ROW_FALLBACK(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8)
+ SWIZZLE_ROW_FALLBACK(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8X8)
+ SWIZZLE_ROW_FALLBACK(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8)
+ SWIZZLE_ROW_FALLBACK(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8A8)
+
+ SWIZZLE_ROW_FALLBACK(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8)
+ SWIZZLE_ROW_FALLBACK(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8X8)
+ SWIZZLE_ROW_FALLBACK(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8)
+ SWIZZLE_ROW_FALLBACK(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8A8)
+ SWIZZLE_ROW_FALLBACK(SurfaceFormat::R8G8B8A8, SurfaceFormat::A8R8G8B8)
+ SWIZZLE_ROW_FALLBACK(SurfaceFormat::R8G8B8X8, SurfaceFormat::X8R8G8B8)
+
+ SWIZZLE_ROW_FALLBACK(SurfaceFormat::A8R8G8B8, SurfaceFormat::R8G8B8A8)
+ SWIZZLE_ROW_FALLBACK(SurfaceFormat::X8R8G8B8, SurfaceFormat::R8G8B8X8)
+ SWIZZLE_ROW_FALLBACK(SurfaceFormat::A8R8G8B8, SurfaceFormat::R8G8B8X8)
+ SWIZZLE_ROW_FALLBACK(SurfaceFormat::X8R8G8B8, SurfaceFormat::R8G8B8A8)
+
+ SWIZZLE_ROW_OPAQUE(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8X8)
+ SWIZZLE_ROW_OPAQUE(SurfaceFormat::B8G8R8X8, SurfaceFormat::B8G8R8A8)
+ SWIZZLE_ROW_OPAQUE(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8X8)
+ SWIZZLE_ROW_OPAQUE(SurfaceFormat::R8G8B8X8, SurfaceFormat::R8G8B8A8)
+ SWIZZLE_ROW_OPAQUE(SurfaceFormat::A8R8G8B8, SurfaceFormat::X8R8G8B8)
+ SWIZZLE_ROW_OPAQUE(SurfaceFormat::X8R8G8B8, SurfaceFormat::A8R8G8B8)
+
+ SWIZZLE_ROW_SWAP(SurfaceFormat::B8G8R8A8, SurfaceFormat::A8R8G8B8)
+ SWIZZLE_ROW_SWAP(SurfaceFormat::B8G8R8A8, SurfaceFormat::X8R8G8B8)
+ SWIZZLE_ROW_SWAP(SurfaceFormat::B8G8R8X8, SurfaceFormat::X8R8G8B8)
+ SWIZZLE_ROW_SWAP(SurfaceFormat::B8G8R8X8, SurfaceFormat::A8R8G8B8)
+ SWIZZLE_ROW_SWAP(SurfaceFormat::A8R8G8B8, SurfaceFormat::B8G8R8A8)
+ SWIZZLE_ROW_SWAP(SurfaceFormat::A8R8G8B8, SurfaceFormat::B8G8R8X8)
+ SWIZZLE_ROW_SWAP(SurfaceFormat::X8R8G8B8, SurfaceFormat::B8G8R8X8)
+ SWIZZLE_ROW_SWAP(SurfaceFormat::X8R8G8B8, SurfaceFormat::B8G8R8A8)
+
+ UNPACK_ROW_RGB(SurfaceFormat::R8G8B8X8)
+ UNPACK_ROW_RGB(SurfaceFormat::R8G8B8A8)
+ UNPACK_ROW_RGB(SurfaceFormat::B8G8R8X8)
+ UNPACK_ROW_RGB(SurfaceFormat::B8G8R8A8)
+ UNPACK_ROW_RGB_TO_ARGB(SurfaceFormat::A8R8G8B8)
+ UNPACK_ROW_RGB_TO_ARGB(SurfaceFormat::X8R8G8B8)
+
+ default:
+ break;
+ }
+
+ MOZ_ASSERT_UNREACHABLE("Unsupported swizzle formats");
+ return nullptr;
+}
+
} // namespace gfx
} // namespace mozilla
diff --git a/gfx/2d/Swizzle.h b/gfx/2d/Swizzle.h
index ed15c33931..b764046f1c 100644
--- a/gfx/2d/Swizzle.h
+++ b/gfx/2d/Swizzle.h
@@ -39,6 +39,25 @@ GFX2D_API bool SwizzleData(const uint8_t* aSrc, int32_t aSrcStride,
int32_t aDstStride, SurfaceFormat aDstFormat,
const IntSize& aSize);
+/**
+ * Swizzles source and writes it to destination. Source and destination may be
+ * the same to swizzle in-place.
+ */
+typedef void (*SwizzleRowFn)(const uint8_t* aSrc, uint8_t* aDst,
+ int32_t aLength);
+
+/**
+ * Get a function pointer to perform premultiplication between two formats.
+ */
+GFX2D_API SwizzleRowFn PremultiplyRow(SurfaceFormat aSrcFormat,
+ SurfaceFormat aDstFormat);
+
+/**
+ * Get a function pointer to perform swizzling between two formats.
+ */
+GFX2D_API SwizzleRowFn SwizzleRow(SurfaceFormat aSrcFormat,
+ SurfaceFormat aDstFormat);
+
} // namespace gfx
} // namespace mozilla
diff --git a/gfx/2d/SwizzleAVX2.cpp b/gfx/2d/SwizzleAVX2.cpp
new file mode 100644
index 0000000000..b38875f115
--- /dev/null
+++ b/gfx/2d/SwizzleAVX2.cpp
@@ -0,0 +1,83 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "Swizzle.h"
+
+#include
+#include
+
+namespace mozilla {
+namespace gfx {
+
+template
+void UnpackRowRGB24_SSSE3(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength);
+
+template
+void UnpackRowRGB24_AVX2(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength) {
+ // Because this implementation will read an additional 8 bytes of data that
+ // is ignored and masked over, we cannot use the accelerated version for the
+ // last 1-10 pixels (3-30 bytes remaining) to guarantee we don't access memory
+ // outside the buffer (we read in 32 byte chunks).
+ if (aLength < 11) {
+ UnpackRowRGB24_SSSE3(aSrc, aDst, aLength);
+ return;
+ }
+
+ // Because we are expanding, we can only process the data back to front in
+ // case we are performing this in place.
+ int32_t alignedRow = (aLength - 4) & ~7;
+ int32_t remainder = aLength - alignedRow;
+
+ const uint8_t* src = aSrc + alignedRow * 3;
+ uint8_t* dst = aDst + alignedRow * 4;
+
+ // Handle any 3-10 remaining pixels.
+ UnpackRowRGB24_SSSE3(src, dst, remainder);
+
+ // Used to shuffle the two final 32-bit words which we ignore into the last
+ // 32-bit word of each 128-bit lane, such that
+ // RGBR GBRG BRGB RGBR GBRG BRGB RGBR GBRG
+ // BRGB RGBR GBRG BRGB ZZZZ ZZZZ ZZZZ ZZZZ
+ // becomes
+ // RGBR GBRG BRGB RGBR GBRG BRGB ZZZZ ZZZZ
+ // RGBR GBRG BRGB RGBR GBRG BRGB ZZZZ ZZZZ
+ const __m256i discardMask = _mm256_set_epi32(7, 5, 4, 3, 6, 2, 1, 0);
+
+ // Used to shuffle 8-bit words within a 128-bit lane, such that we transform
+ // RGBR GBRG BRGB RGBR GBRG BRGB ZZZZ ZZZZ
+ // into
+ // RGBZ RGBZ RGBZ RGBZ RGBZ RGBZ RGBZ RGBZ
+ // or
+ // BGRZ BGRZ BGRZ BGRZ BGRZ BGRZ BGRZ BGRZ
+ const __m256i colorMask =
+ aSwapRB ? _mm256_set_epi8(15, 9, 10, 11, 14, 6, 7, 8, 13, 3, 4, 5, 12, 0,
+ 1, 2, 15, 9, 10, 11, 14, 6, 7, 8, 13, 3, 4, 5,
+ 12, 0, 1, 2)
+ : _mm256_set_epi8(15, 11, 10, 9, 14, 8, 7, 6, 13, 5, 4, 3, 12, 2,
+ 1, 0, 15, 11, 10, 9, 14, 8, 7, 6, 13, 5, 4, 3,
+ 12, 2, 1, 0);
+
+ // Used to transform RGBZ/BGRZ to RGBX/BGRX, or force the alpha opaque.
+ const __m256i alphaMask = _mm256_set1_epi32(0xFF000000);
+
+ // Process all 8-pixel chunks as one vector.
+ src -= 8 * 3;
+ dst -= 8 * 4;
+ while (src >= aSrc) {
+ __m256i px = _mm256_loadu_si256(reinterpret_cast(src));
+ px = _mm256_permutevar8x32_epi32(px, discardMask);
+ px = _mm256_shuffle_epi8(px, colorMask);
+ px = _mm256_or_si256(px, alphaMask);
+ _mm256_storeu_si256(reinterpret_cast<__m256i*>(dst), px);
+ src -= 8 * 3;
+ dst -= 8 * 4;
+ }
+}
+
+// Force instantiation of swizzle variants here.
+template void UnpackRowRGB24_AVX2(const uint8_t*, uint8_t*, int32_t);
+template void UnpackRowRGB24_AVX2(const uint8_t*, uint8_t*, int32_t);
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/2d/SwizzleNEON.cpp b/gfx/2d/SwizzleNEON.cpp
index 3ad2ac8781..4f7d749259 100644
--- a/gfx/2d/SwizzleNEON.cpp
+++ b/gfx/2d/SwizzleNEON.cpp
@@ -83,6 +83,36 @@ PremultiplyVector_NEON(const uint16x8_t& aSrc) {
return vsriq_n_u16(ga, rb, 8);
}
+template
+static MOZ_ALWAYS_INLINE void PremultiplyChunk_NEON(const uint8_t*& aSrc,
+ uint8_t*& aDst,
+ int32_t aAlignedRow,
+ int32_t aRemainder) {
+ // Process all 4-pixel chunks as one vector.
+ for (const uint8_t* end = aSrc + aAlignedRow; aSrc < end;) {
+ uint16x8_t px = vld1q_u16(reinterpret_cast(aSrc));
+ px = PremultiplyVector_NEON(px);
+ vst1q_u16(reinterpret_cast(aDst), px);
+ aSrc += 4 * 4;
+ aDst += 4 * 4;
+ }
+
+ // Handle any 1-3 remaining pixels.
+ if (aRemainder) {
+ uint16x8_t px = LoadRemainder_NEON(aSrc, aRemainder);
+ px = PremultiplyVector_NEON(px);
+ StoreRemainder_NEON(aDst, aRemainder, px);
+ }
+}
+
+template
+void PremultiplyRow_NEON(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength) {
+ int32_t alignedRow = 4 * (aLength & ~3);
+ int32_t remainder = aLength & 3;
+ PremultiplyChunk_NEON(aSrc, aDst, alignedRow,
+ remainder);
+}
+
template
void Premultiply_NEON(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
int32_t aDstGap, IntSize aSize) {
@@ -93,28 +123,22 @@ void Premultiply_NEON(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
aDstGap += 4 * remainder;
for (int32_t height = aSize.height; height > 0; height--) {
- // Process all 4-pixel chunks as one vector.
- for (const uint8_t* end = aSrc + alignedRow; aSrc < end;) {
- uint16x8_t px = vld1q_u16(reinterpret_cast(aSrc));
- px = PremultiplyVector_NEON(px);
- vst1q_u16(reinterpret_cast(aDst), px);
- aSrc += 4 * 4;
- aDst += 4 * 4;
- }
-
- // Handle any 1-3 remaining pixels.
- if (remainder) {
- uint16x8_t px = LoadRemainder_NEON(aSrc, remainder);
- px = PremultiplyVector_NEON(px);
- StoreRemainder_NEON(aDst, remainder, px);
- }
-
+ PremultiplyChunk_NEON(aSrc, aDst, alignedRow,
+ remainder);
aSrc += aSrcGap;
aDst += aDstGap;
}
}
// Force instantiation of premultiply variants here.
+template void PremultiplyRow_NEON(const uint8_t*, uint8_t*,
+ int32_t);
+template void PremultiplyRow_NEON(const uint8_t*, uint8_t*,
+ int32_t);
+template void PremultiplyRow_NEON(const uint8_t*, uint8_t*,
+ int32_t);
+template void PremultiplyRow_NEON(const uint8_t*, uint8_t*,
+ int32_t);
template void Premultiply_NEON(const uint8_t*, int32_t, uint8_t*,
int32_t, IntSize);
template void Premultiply_NEON(const uint8_t*, int32_t, uint8_t*,
@@ -256,7 +280,7 @@ template void Unpremultiply_NEON(const uint8_t*, int32_t, uint8_t*,
// Swizzle a vector of 4 pixels providing swaps and opaquifying.
template
-MOZ_ALWAYS_INLINE uint16x8_t SwizzleVector_NEON(const uint16x8_t& aSrc) {
+static MOZ_ALWAYS_INLINE uint16x8_t SwizzleVector_NEON(const uint16x8_t& aSrc) {
// Swap R and B, then add to G and A (forced to 255):
// (((src>>16) | (src << 16)) & 0x00FF00FF) |
// ((src | 0xFF000000) & ~0x00FF00FF)
@@ -273,7 +297,7 @@ MOZ_ALWAYS_INLINE uint16x8_t SwizzleVector_NEON(const uint16x8_t& aSrc) {
// Optimized implementations for when there is no R and B swap.
template<>
-MOZ_ALWAYS_INLINE uint16x8_t
+static MOZ_ALWAYS_INLINE uint16x8_t
SwizzleVector_NEON(const uint16x8_t& aSrc)
{
// Force alpha to 255.
@@ -281,13 +305,42 @@ SwizzleVector_NEON(const uint16x8_t& aSrc)
}
template<>
-MOZ_ALWAYS_INLINE uint16x8_t
+static MOZ_ALWAYS_INLINE uint16x8_t
SwizzleVector_NEON(const uint16x8_t& aSrc)
{
return aSrc;
}
#endif
+template
+static MOZ_ALWAYS_INLINE void SwizzleChunk_NEON(const uint8_t*& aSrc,
+ uint8_t*& aDst,
+ int32_t aAlignedRow,
+ int32_t aRemainder) {
+ // Process all 4-pixel chunks as one vector.
+ for (const uint8_t* end = aSrc + aAlignedRow; aSrc < end;) {
+ uint16x8_t px = vld1q_u16(reinterpret_cast(aSrc));
+ px = SwizzleVector_NEON(px);
+ vst1q_u16(reinterpret_cast(aDst), px);
+ aSrc += 4 * 4;
+ aDst += 4 * 4;
+ }
+
+ // Handle any 1-3 remaining pixels.
+ if (aRemainder) {
+ uint16x8_t px = LoadRemainder_NEON(aSrc, aRemainder);
+ px = SwizzleVector_NEON(px);
+ StoreRemainder_NEON(aDst, aRemainder, px);
+ }
+}
+
+template
+void SwizzleRow_NEON(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength) {
+ int32_t alignedRow = 4 * (aLength & ~3);
+ int32_t remainder = aLength & 3;
+ SwizzleChunk_NEON(aSrc, aDst, alignedRow, remainder);
+}
+
template
void Swizzle_NEON(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
int32_t aDstGap, IntSize aSize) {
@@ -298,28 +351,16 @@ void Swizzle_NEON(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
aDstGap += 4 * remainder;
for (int32_t height = aSize.height; height > 0; height--) {
- // Process all 4-pixel chunks as one vector.
- for (const uint8_t* end = aSrc + alignedRow; aSrc < end;) {
- uint16x8_t px = vld1q_u16(reinterpret_cast(aSrc));
- px = SwizzleVector_NEON(px);
- vst1q_u16(reinterpret_cast(aDst), px);
- aSrc += 4 * 4;
- aDst += 4 * 4;
- }
-
- // Handle any 1-3 remaining pixels.
- if (remainder) {
- uint16x8_t px = LoadRemainder_NEON(aSrc, remainder);
- px = SwizzleVector_NEON(px);
- StoreRemainder_NEON(aDst, remainder, px);
- }
-
+ SwizzleChunk_NEON(aSrc, aDst, alignedRow,
+ remainder);
aSrc += aSrcGap;
aDst += aDstGap;
}
}
// Force instantiation of swizzle variants here.
+template void SwizzleRow_NEON(const uint8_t*, uint8_t*, int32_t);
+template void SwizzleRow_NEON(const uint8_t*, uint8_t*, int32_t);
template void Swizzle_NEON(const uint8_t*, int32_t, uint8_t*,
int32_t, IntSize);
template void Swizzle_NEON(const uint8_t*, int32_t, uint8_t*,
diff --git a/gfx/2d/SwizzleSSE2.cpp b/gfx/2d/SwizzleSSE2.cpp
index 1efd9af10a..4d61f52e8a 100644
--- a/gfx/2d/SwizzleSSE2.cpp
+++ b/gfx/2d/SwizzleSSE2.cpp
@@ -86,6 +86,38 @@ static MOZ_ALWAYS_INLINE __m128i PremultiplyVector_SSE2(const __m128i& aSrc) {
return _mm_or_si128(rb, ga);
}
+// Premultiply vector of aAlignedRow + aRemainder pixels.
+template
+static MOZ_ALWAYS_INLINE void PremultiplyChunk_SSE2(const uint8_t*& aSrc,
+ uint8_t*& aDst,
+ int32_t aAlignedRow,
+ int32_t aRemainder) {
+ // Process all 4-pixel chunks as one vector.
+ for (const uint8_t* end = aSrc + aAlignedRow; aSrc < end;) {
+ __m128i px = _mm_loadu_si128(reinterpret_cast(aSrc));
+ px = PremultiplyVector_SSE2(px);
+ _mm_storeu_si128(reinterpret_cast<__m128i*>(aDst), px);
+ aSrc += 4 * 4;
+ aDst += 4 * 4;
+ }
+
+ // Handle any 1-3 remaining pixels.
+ if (aRemainder) {
+ __m128i px = LoadRemainder_SSE2(aSrc, aRemainder);
+ px = PremultiplyVector_SSE2(px);
+ StoreRemainder_SSE2(aDst, aRemainder, px);
+ }
+}
+
+// Premultiply vector of aLength pixels.
+template
+void PremultiplyRow_SSE2(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength) {
+ int32_t alignedRow = 4 * (aLength & ~3);
+ int32_t remainder = aLength & 3;
+ PremultiplyChunk_SSE2(aSrc, aDst, alignedRow,
+ remainder);
+}
+
template
void Premultiply_SSE2(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
int32_t aDstGap, IntSize aSize) {
@@ -96,28 +128,22 @@ void Premultiply_SSE2(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
aDstGap += 4 * remainder;
for (int32_t height = aSize.height; height > 0; height--) {
- // Process all 4-pixel chunks as one vector.
- for (const uint8_t* end = aSrc + alignedRow; aSrc < end;) {
- __m128i px = _mm_loadu_si128(reinterpret_cast(aSrc));
- px = PremultiplyVector_SSE2(px);
- _mm_storeu_si128(reinterpret_cast<__m128i*>(aDst), px);
- aSrc += 4 * 4;
- aDst += 4 * 4;
- }
-
- // Handle any 1-3 remaining pixels.
- if (remainder) {
- __m128i px = LoadRemainder_SSE2(aSrc, remainder);
- px = PremultiplyVector_SSE2(px);
- StoreRemainder_SSE2(aDst, remainder, px);
- }
-
+ PremultiplyChunk_SSE2(aSrc, aDst, alignedRow,
+ remainder);
aSrc += aSrcGap;
aDst += aDstGap;
}
}
// Force instantiation of premultiply variants here.
+template void PremultiplyRow_SSE2(const uint8_t*, uint8_t*,
+ int32_t);
+template void PremultiplyRow_SSE2(const uint8_t*, uint8_t*,
+ int32_t);
+template void PremultiplyRow_SSE2(const uint8_t*, uint8_t*,
+ int32_t);
+template void PremultiplyRow_SSE2(const uint8_t*, uint8_t*,
+ int32_t);
template void Premultiply_SSE2(const uint8_t*, int32_t, uint8_t*,
int32_t, IntSize);
template void Premultiply_SSE2(const uint8_t*, int32_t, uint8_t*,
@@ -291,6 +317,35 @@ SwizzleVector_SSE2(const __m128i& aSrc)
}
#endif
+template
+static MOZ_ALWAYS_INLINE void SwizzleChunk_SSE2(const uint8_t*& aSrc,
+ uint8_t*& aDst,
+ int32_t aAlignedRow,
+ int32_t aRemainder) {
+ // Process all 4-pixel chunks as one vector.
+ for (const uint8_t* end = aSrc + aAlignedRow; aSrc < end;) {
+ __m128i px = _mm_loadu_si128(reinterpret_cast(aSrc));
+ px = SwizzleVector_SSE2(px);
+ _mm_storeu_si128(reinterpret_cast<__m128i*>(aDst), px);
+ aSrc += 4 * 4;
+ aDst += 4 * 4;
+ }
+
+ // Handle any 1-3 remaining pixels.
+ if (aRemainder) {
+ __m128i px = LoadRemainder_SSE2(aSrc, aRemainder);
+ px = SwizzleVector_SSE2(px);
+ StoreRemainder_SSE2(aDst, aRemainder, px);
+ }
+}
+
+template
+void SwizzleRow_SSE2(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength) {
+ int32_t alignedRow = 4 * (aLength & ~3);
+ int32_t remainder = aLength & 3;
+ SwizzleChunk_SSE2(aSrc, aDst, alignedRow, remainder);
+}
+
template
void Swizzle_SSE2(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
int32_t aDstGap, IntSize aSize) {
@@ -301,28 +356,15 @@ void Swizzle_SSE2(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
aDstGap += 4 * remainder;
for (int32_t height = aSize.height; height > 0; height--) {
- // Process all 4-pixel chunks as one vector.
- for (const uint8_t* end = aSrc + alignedRow; aSrc < end;) {
- __m128i px = _mm_loadu_si128(reinterpret_cast(aSrc));
- px = SwizzleVector_SSE2(px);
- _mm_storeu_si128(reinterpret_cast<__m128i*>(aDst), px);
- aSrc += 4 * 4;
- aDst += 4 * 4;
- }
-
- // Handle any 1-3 remaining pixels.
- if (remainder) {
- __m128i px = LoadRemainder_SSE2(aSrc, remainder);
- px = SwizzleVector_SSE2(px);
- StoreRemainder_SSE2(aDst, remainder, px);
- }
-
+ SwizzleChunk_SSE2(aSrc, aDst, alignedRow, remainder);
aSrc += aSrcGap;
aDst += aDstGap;
}
}
// Force instantiation of swizzle variants here.
+template void SwizzleRow_SSE2(const uint8_t*, uint8_t*, int32_t);
+template void SwizzleRow_SSE2(const uint8_t*, uint8_t*, int32_t);
template void Swizzle_SSE2(const uint8_t*, int32_t, uint8_t*,
int32_t, IntSize);
template void Swizzle_SSE2(const uint8_t*, int32_t, uint8_t*,
diff --git a/gfx/2d/SwizzleSSSE3.cpp b/gfx/2d/SwizzleSSSE3.cpp
new file mode 100644
index 0000000000..39df76e4be
--- /dev/null
+++ b/gfx/2d/SwizzleSSSE3.cpp
@@ -0,0 +1,65 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "Swizzle.h"
+
+#include
+#include
+
+namespace mozilla {
+namespace gfx {
+
+template
+void UnpackRowRGB24(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength);
+
+template
+void UnpackRowRGB24_SSSE3(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength) {
+ // Because this implementation will read an additional 4 bytes of data that
+ // is ignored and masked over, we cannot use the accelerated version for the
+ // last 1-5 pixels (3-15 bytes remaining) to guarantee we don't access memory
+ // outside the buffer (we read in 16 byte chunks).
+ if (aLength < 6) {
+ UnpackRowRGB24(aSrc, aDst, aLength);
+ return;
+ }
+
+ // Because we are expanding, we can only process the data back to front in
+ // case we are performing this in place.
+ int32_t alignedRow = (aLength - 2) & ~3;
+ int32_t remainder = aLength - alignedRow;
+
+ const uint8_t* src = aSrc + alignedRow * 3;
+ uint8_t* dst = aDst + alignedRow * 4;
+
+ // Handle 2-5 remaining pixels.
+ UnpackRowRGB24(src, dst, remainder);
+
+ __m128i mask;
+ if (aSwapRB) {
+ mask = _mm_set_epi8(15, 9, 10, 11, 14, 6, 7, 8, 13, 3, 4, 5, 12, 0, 1, 2);
+ } else {
+ mask = _mm_set_epi8(15, 11, 10, 9, 14, 8, 7, 6, 13, 5, 4, 3, 12, 2, 1, 0);
+ }
+
+ __m128i alpha = _mm_set1_epi32(0xFF000000);
+
+ // Process all 4-pixel chunks as one vector.
+ src -= 4 * 3;
+ dst -= 4 * 4;
+ while (src >= aSrc) {
+ __m128i px = _mm_loadu_si128(reinterpret_cast(src));
+ px = _mm_shuffle_epi8(px, mask);
+ px = _mm_or_si128(px, alpha);
+ _mm_storeu_si128(reinterpret_cast<__m128i*>(dst), px);
+ src -= 4 * 3;
+ dst -= 4 * 4;
+ }
+}
+
+// Force instantiation of swizzle variants here.
+template void UnpackRowRGB24_SSSE3(const uint8_t*, uint8_t*, int32_t);
+template void UnpackRowRGB24_SSSE3(const uint8_t*, uint8_t*, int32_t);
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/2d/Types.h b/gfx/2d/Types.h
index e4ec9c82c5..38e26f1c52 100644
--- a/gfx/2d/Types.h
+++ b/gfx/2d/Types.h
@@ -36,6 +36,7 @@ enum class SurfaceType : int8_t {
CAPTURE, /* Data from a DrawTargetCapture */
DATA_RECYCLING_SHARED, /* Data surface using shared memory */
OFFSET, /* Offset */
+ DATA_ALIGNED, /* Data surface using aligned heap memory */
};
enum class SurfaceFormat : int8_t {
@@ -87,15 +88,63 @@ enum class SurfaceFormat : int8_t {
// value.
#if MOZ_LITTLE_ENDIAN()
A8R8G8B8_UINT32 = B8G8R8A8, // 0xAARRGGBB
- X8R8G8B8_UINT32 = B8G8R8X8 // 0x00RRGGBB
+ X8R8G8B8_UINT32 = B8G8R8X8, // 0x00RRGGBB
#elif MOZ_BIG_ENDIAN()
A8R8G8B8_UINT32 = A8R8G8B8, // 0xAARRGGBB
- X8R8G8B8_UINT32 = X8R8G8B8 // 0x00RRGGBB
+ X8R8G8B8_UINT32 = X8R8G8B8, // 0x00RRGGBB
#else
# error "bad endianness"
#endif
+
+ // The following values are OS and endian-independent synonyms.
+ //
+ // TODO(aosmond): When everything blocking bug 1581828 has been resolved, we
+ // can make this use R8B8G8A8 and R8B8G8X8 for non-Windows platforms.
+ OS_RGBA = A8R8G8B8_UINT32,
+ OS_RGBX = X8R8G8B8_UINT32
};
+// Represents the bit-shifts required to access color channels when the layout
+// is viewed as a uint32_t value.
+enum class SurfaceFormatBit : uint32_t {
+#if MOZ_LITTLE_ENDIAN()
+ R8G8B8A8_R = 0,
+ R8G8B8A8_G = 8,
+ R8G8B8A8_B = 16,
+ R8G8B8A8_A = 24,
+#elif MOZ_BIG_ENDIAN()
+ R8G8B8A8_A = 0,
+ R8G8B8A8_B = 8,
+ R8G8B8A8_G = 16,
+ R8G8B8A8_R = 24,
+#else
+# error "bad endianness"
+#endif
+
+ // The following values are endian-independent for A8R8G8B8_UINT32.
+ A8R8G8B8_UINT32_B = 0,
+ A8R8G8B8_UINT32_G = 8,
+ A8R8G8B8_UINT32_R = 16,
+ A8R8G8B8_UINT32_A = 24,
+
+ // The following values are OS and endian-independent.
+ //
+ // TODO(aosmond): When everything blocking bug 1581828 has been resolved, we
+ // can make this use R8G8B8A8_X for non-Windows platforms.
+ OS_R = A8R8G8B8_UINT32_R,
+ OS_G = A8R8G8B8_UINT32_G,
+ OS_B = A8R8G8B8_UINT32_B,
+ OS_A = A8R8G8B8_UINT32_A,
+};
+
+inline uint32_t operator<<(uint8_t a, SurfaceFormatBit b) {
+ return a << static_cast(b);
+}
+
+inline uint32_t operator>>(uint32_t a, SurfaceFormatBit b) {
+ return a >> static_cast(b);
+}
+
static inline int BytesPerPixel(SurfaceFormat aFormat) {
switch (aFormat) {
case SurfaceFormat::A8:
diff --git a/gfx/2d/moz.build b/gfx/2d/moz.build
index 5f666e99d2..7a88f7f63a 100644
--- a/gfx/2d/moz.build
+++ b/gfx/2d/moz.build
@@ -142,7 +142,9 @@ if CONFIG['INTEL_ARCHITECTURE'] and not CONFIG['THE_SSE1']:
'FilterProcessingSSE2.cpp',
'ImageScalingSSE2.cpp',
'ssse3-scaler.c',
+# 'SwizzleAVX2.cpp',
'SwizzleSSE2.cpp',
+ 'SwizzleSSSE3.cpp',
]
DEFINES['USE_SSE2'] = True
# The file uses SSE2 intrinsics, so it needs special compile flags on some
@@ -150,7 +152,9 @@ if CONFIG['INTEL_ARCHITECTURE'] and not CONFIG['THE_SSE1']:
SOURCES['BlurSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
SOURCES['FilterProcessingSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
SOURCES['ImageScalingSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
+# SOURCES['SwizzleAVX2.cpp'].flags += ['-mavx2']
SOURCES['SwizzleSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
+ SOURCES['SwizzleSSSE3.cpp'].flags += CONFIG['SSSE3_FLAGS']
SOURCES['ssse3-scaler.c'].flags += CONFIG['SSSE3_FLAGS']
elif CONFIG['CPU_ARCH'].startswith('mips'):
SOURCES += [
diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h
index e87f23f4c7..a60d95eb64 100644
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -186,10 +186,8 @@ enum class GLRenderer {
Other
};
-class GLContext : public GenericAtomicRefCounted,
- public SupportsWeakPtr {
+class GLContext : public GenericAtomicRefCounted, public SupportsWeakPtr {
public:
- MOZ_DECLARE_WEAKREFERENCE_TYPENAME(GLContext)
static MOZ_THREAD_LOCAL(uintptr_t) sCurrentContext;
bool mImplicitMakeCurrent = false;
diff --git a/gfx/gl/SharedSurface.h b/gfx/gl/SharedSurface.h
index 103037e2a4..5a45df6fe6 100644
--- a/gfx/gl/SharedSurface.h
+++ b/gfx/gl/SharedSurface.h
@@ -237,12 +237,8 @@ class RefQueue {
}
};
-class SurfaceFactory : public SupportsWeakPtr {
+class SurfaceFactory : public SupportsWeakPtr {
public:
- // Should use the VIRTUAL version, but it's currently incompatible
- // with SupportsWeakPtr. (bug 1049278)
- MOZ_DECLARE_WEAKREFERENCE_TYPENAME(SurfaceFactory)
-
const SharedSurfaceType mType;
GLContext* const mGL;
const SurfaceCaps mCaps;
diff --git a/gfx/ipc/GPUProcessManager.h b/gfx/ipc/GPUProcessManager.h
index f7f76c832c..90a7a4c5e3 100644
--- a/gfx/ipc/GPUProcessManager.h
+++ b/gfx/ipc/GPUProcessManager.h
@@ -43,6 +43,7 @@ class CompositorWidget;
namespace dom {
class ContentParent;
class BrowserParent;
+class Pref;
} // namespace dom
namespace ipc {
class GeckoChildProcessHost;
diff --git a/gfx/layers/Compositor.h b/gfx/layers/Compositor.h
index a354ece6a4..36ff31463e 100644
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -300,12 +300,6 @@ class Compositor : public TextureSourceProvider {
*/
virtual void SetDestinationSurfaceSize(const gfx::IntSize& aSize) = 0;
- /**
- * Declare an offset to use when rendering layers. This will be ignored when
- * rendering to a target instead of the screen.
- */
- virtual void SetScreenRenderOffset(const ScreenPoint& aOffset) = 0;
-
void DrawGeometry(const gfx::Rect& aRect, const gfx::IntRect& aClipRect,
const EffectChain& aEffectChain, gfx::Float aOpacity,
const gfx::Matrix4x4& aTransform,
diff --git a/gfx/layers/ImageContainer.h b/gfx/layers/ImageContainer.h
index 6a5e590d32..5f5e67d72d 100644
--- a/gfx/layers/ImageContainer.h
+++ b/gfx/layers/ImageContainer.h
@@ -265,14 +265,12 @@ class ImageContainerListener final {
* synchronously updates the shared state to point to the new image and the old
* image is immediately released (not true in Normal or Asynchronous modes).
*/
-class ImageContainer final : public SupportsWeakPtr {
+class ImageContainer final : public SupportsWeakPtr {
friend class ImageContainerChild;
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageContainer)
public:
- MOZ_DECLARE_WEAKREFERENCE_TYPENAME(ImageContainer)
-
enum Mode { SYNCHRONOUS = 0x0, ASYNCHRONOUS = 0x01 };
static const uint64_t sInvalidAsyncContainerId = 0;
diff --git a/gfx/layers/LayersLogging.cpp b/gfx/layers/LayersLogging.cpp
index 7ff66680b9..08bc26662b 100644
--- a/gfx/layers/LayersLogging.cpp
+++ b/gfx/layers/LayersLogging.cpp
@@ -442,6 +442,12 @@ void AppendToString(std::stringstream& aStream, gfx::SurfaceType aType,
case SurfaceType::DATA_SHARED:
aStream << "SurfaceType::DATA_SHARED";
break;
+ case SurfaceType::DATA_RECYCLING_SHARED:
+ aStream << "SurfaceType::DATA_RECYCLING_SHARED";
+ break;
+ case SurfaceType::DATA_ALIGNED:
+ aStream << "SurfaceType::DATA_ALIGNED";
+ break;
default:
NS_ERROR("unknown surface type");
aStream << "???";
diff --git a/gfx/layers/SourceSurfaceSharedData.cpp b/gfx/layers/SourceSurfaceSharedData.cpp
index 32cbfb27df..e01a8b0943 100644
--- a/gfx/layers/SourceSurfaceSharedData.cpp
+++ b/gfx/layers/SourceSurfaceSharedData.cpp
@@ -88,26 +88,20 @@ void SourceSurfaceSharedData::GuaranteePersistance() {
// Shared memory is not unmapped until we release SourceSurfaceSharedData.
}
-void SourceSurfaceSharedData::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
- size_t& aHeapSizeOut,
- size_t& aNonHeapSizeOut,
- size_t& aExtHandlesOut
-#ifdef MOZ_BUILD_WEBRENDER
- ,
- uint64_t& aExtIdOut
-#endif
-) const {
+void SourceSurfaceSharedData::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+ SizeOfInfo& aInfo) const {
MutexAutoLock lock(mMutex);
+ aInfo.AddType(SurfaceType::DATA_SHARED);
if (mBuf) {
- aNonHeapSizeOut += GetAlignedDataLength();
+ aInfo.mNonHeapBytes = GetAlignedDataLength();
}
if (!mClosed) {
- ++aExtHandlesOut;
+ aInfo.mExternalHandles = 1;
}
#ifdef MOZ_BUILD_WEBRENDER
Maybe extId = SharedSurfacesChild::GetExternalId(this);
if (extId) {
- aExtIdOut = wr::AsUint64(extId.ref());
+ aInfo.mExternalId = wr::AsUint64(extId.ref());
}
#endif
}
diff --git a/gfx/layers/SourceSurfaceSharedData.h b/gfx/layers/SourceSurfaceSharedData.h
index 3e4925505d..e007b713d9 100644
--- a/gfx/layers/SourceSurfaceSharedData.h
+++ b/gfx/layers/SourceSurfaceSharedData.h
@@ -156,13 +156,8 @@ class SourceSurfaceSharedData final : public DataSourceSurface {
void GuaranteePersistance() override;
- void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, size_t& aHeapSizeOut,
- size_t& aNonHeapSizeOut, size_t& aExtHandlesOut
-#ifdef MOZ_BUILD_WEBRENDER
- ,
- uint64_t& aExtIdOut
-#endif
- ) const override;
+ void SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+ SizeOfInfo& aInfo) const override;
bool OnHeap() const override { return false; }
diff --git a/gfx/layers/SourceSurfaceVolatileData.cpp b/gfx/layers/SourceSurfaceVolatileData.cpp
index 9fea6c415d..264077cc46 100644
--- a/gfx/layers/SourceSurfaceVolatileData.cpp
+++ b/gfx/layers/SourceSurfaceVolatileData.cpp
@@ -31,21 +31,16 @@ void SourceSurfaceVolatileData::GuaranteePersistance() {
MOZ_ASSERT_UNREACHABLE("Should use SourceSurfaceRawData wrapper!");
}
-void SourceSurfaceVolatileData::AddSizeOfExcludingThis(
- MallocSizeOf aMallocSizeOf, size_t& aHeapSizeOut, size_t& aNonHeapSizeOut,
- size_t& aExtHandlesOut
-#ifdef MOZ_BUILD_WEBRENDER
- ,
- uint64_t& aExtIdOut
-#endif
-) const {
+void SourceSurfaceVolatileData::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+ SizeOfInfo& aInfo) const {
+ aInfo.AddType(SurfaceType::DATA);
if (mVBuf) {
- aHeapSizeOut += mVBuf->HeapSizeOfExcludingThis(aMallocSizeOf);
- aNonHeapSizeOut += mVBuf->NonHeapSizeOfExcludingThis();
+ aInfo.mHeapBytes = mVBuf->HeapSizeOfExcludingThis(aMallocSizeOf);
+ aInfo.mNonHeapBytes = mVBuf->NonHeapSizeOfExcludingThis();
#ifdef ANDROID
if (!mVBuf->OnHeap()) {
// Volatile buffers keep a file handle open on Android.
- ++aExtHandlesOut;
+ aInfo.mExternalHandles = 1;
}
#endif
}
diff --git a/gfx/layers/SourceSurfaceVolatileData.h b/gfx/layers/SourceSurfaceVolatileData.h
index fb15c0c439..0923582a67 100644
--- a/gfx/layers/SourceSurfaceVolatileData.h
+++ b/gfx/layers/SourceSurfaceVolatileData.h
@@ -42,13 +42,8 @@ class SourceSurfaceVolatileData : public DataSourceSurface {
void GuaranteePersistance() override;
- void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, size_t& aHeapSizeOut,
- size_t& aNonHeapSizeOut, size_t& aExtHandlesOut
-#ifdef MOZ_BUILD_WEBRENDER
- ,
- uint64_t& aExtIdOut
-#endif
- ) const override;
+ void SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+ SizeOfInfo& aInfo) const override;
bool OnHeap() const override { return mVBuf->OnHeap(); }
diff --git a/gfx/layers/apz/src/APZCTreeManager.cpp b/gfx/layers/apz/src/APZCTreeManager.cpp
index ece40043f6..80fa3de976 100644
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -22,9 +22,6 @@
#include "mozilla/gfx/GPUParent.h" // for GPUParent
#include "mozilla/gfx/Logging.h" // for gfx::TreeLog
#include "mozilla/gfx/Point.h" // for Point
-#ifdef MOZ_WIDGET_ANDROID
-# include "mozilla/jni/Utils.h" // for jni::IsFennec
-#endif
#include "mozilla/layers/APZSampler.h" // for APZSampler
#include "mozilla/layers/APZThreadUtils.h" // for AssertOnControllerThread, etc
#include "mozilla/layers/APZUpdater.h" // for APZUpdater
@@ -300,11 +297,6 @@ APZCTreeManager::APZCTreeManager(LayersId aRootLayersId)
[self] { self->mFlushObserver = new CheckerboardFlushObserver(self); }));
AsyncPanZoomController::InitializeGlobalState();
mApzcTreeLog.ConditionOnPrefFunction(StaticPrefs::apz_printtree);
-#if defined(MOZ_WIDGET_ANDROID)
- if (jni::IsFennec()) {
- mToolbarAnimator = new AndroidDynamicToolbarAnimator(this);
- }
-#endif // (MOZ_WIDGET_ANDROID)
}
APZCTreeManager::~APZCTreeManager() = default;
@@ -1402,31 +1394,6 @@ APZEventResult APZCTreeManager::ReceiveInputEvent(InputData& aEvent) {
// Use a RAII class for updating the focus sequence number of this event
AutoFocusSequenceNumberSetter focusSetter(mFocusState, aEvent);
-#if defined(MOZ_WIDGET_ANDROID)
- if (mToolbarAnimator) {
- ScreenPoint scrollOffset;
- {
- RecursiveMutexAutoLock lock(mTreeLock);
- RefPtr apzc = FindRootContentOrRootApzc();
- if (apzc) {
- scrollOffset = ViewAs(
- apzc->GetCurrentAsyncScrollOffset(
- AsyncPanZoomController::eForHitTesting),
- PixelCastJustification::ScreenIsParentLayerForRoot);
- }
- }
- RefPtr self = this;
- nsEventStatus isConsumed =
- mToolbarAnimator->ReceiveInputEvent(self, aEvent, scrollOffset);
- // Check if the mToolbarAnimator consumed the event.
- if (isConsumed == nsEventStatus_eConsumeNoDefault) {
- APZCTM_LOG("Dynamic toolbar consumed event");
- result.mStatus = isConsumed;
- return result;
- }
- }
-#endif // (MOZ_WIDGET_ANDROID)
-
CompositorHitTestInfo hitResult = CompositorHitTestInvisibleToHit;
switch (aEvent.mInputType) {
case MULTITOUCH_INPUT: {
@@ -2071,9 +2038,9 @@ APZEventResult APZCTreeManager::ProcessTouchInputForScrollbarDrag(
// Synthesize a mouse event based on the touch event, so that we can
// reuse code in InputQueue and APZC for handling scrollbar mouse-drags.
MouseInput mouseInput{MultiTouchTypeToMouseType(aTouchInput.mType),
- MouseInput::LEFT_BUTTON,
+ MouseInput::PRIMARY_BUTTON,
dom::MouseEvent_Binding::MOZ_SOURCE_TOUCH,
- MouseButtonsFlag::eLeftFlag,
+ MouseButtonsFlag::ePrimaryFlag,
aTouchInput.mTouches[0].mScreenPoint,
aTouchInput.mTime,
aTouchInput.mTimeStamp,
@@ -2310,17 +2277,6 @@ void APZCTreeManager::ProcessUnhandledEvent(LayoutDeviceIntPoint* aRefPoint,
*aOutFocusSequenceNumber = mFocusState.LastAPZProcessedEvent();
}
-void APZCTreeManager::ProcessDynamicToolbarMovement(uint32_t aStartTimestampMs,
- uint32_t aEndTimestampMs,
- ScreenCoord aDeltaY) {
- if (mApzcForInputBlock) {
- mApzcForInputBlock->HandleDynamicToolbarMovement(
- aStartTimestampMs, aEndTimestampMs,
- ViewAs(
- aDeltaY, PixelCastJustification::ScreenIsParentLayerForRoot));
- }
-}
-
void APZCTreeManager::SetKeyboardMap(const KeyboardMap& aKeyboardMap) {
APZThreadUtils::AssertOnControllerThread();
@@ -2487,23 +2443,9 @@ void APZCTreeManager::FlushRepaintsToClearScreenToGeckoTransform() {
});
}
-void APZCTreeManager::AdjustScrollForSurfaceShift(const ScreenPoint& aShift) {
- RecursiveMutexAutoLock lock(mTreeLock);
- RefPtr apzc = FindRootContentOrRootApzc();
- if (apzc) {
- apzc->AdjustScrollForSurfaceShift(aShift);
- }
-}
-
void APZCTreeManager::ClearTree() {
AssertOnUpdaterThread();
-#if defined(MOZ_WIDGET_ANDROID)
- if (mToolbarAnimator) {
- mToolbarAnimator->ClearTreeManager();
- }
-#endif
-
// Ensure that no references to APZCs are alive in any lingering input
// blocks. This breaks cycles from InputBlockState::mTargetApzc back to
// the InputQueue.
@@ -3100,31 +3042,6 @@ AsyncPanZoomController* APZCTreeManager::FindRootContentApzcForLayersId(
return resultNode ? resultNode->GetApzc() : nullptr;
}
-AsyncPanZoomController* APZCTreeManager::FindRootContentOrRootApzc() const {
- mTreeLock.AssertCurrentThreadIn();
-
- // Note: this is intended to find the same "root" that would be found
- // by AsyncCompositionManager::ApplyAsyncContentTransformToTree inside
- // the MOZ_WIDGET_ANDROID block. That is, it should find the RCD node if there
- // is one, or the root APZC if there is not.
- // Since BreadthFirstSearch is a pre-order search, we first do a search for
- // the RCD, and then if we don't find one, we do a search for the root APZC.
- HitTestingTreeNode* resultNode = BreadthFirstSearch(
- mRootNode.get(), [](HitTestingTreeNode* aNode) {
- AsyncPanZoomController* apzc = aNode->GetApzc();
- return apzc && apzc->IsRootContent();
- });
- if (resultNode) {
- return resultNode->GetApzc();
- }
- resultNode = BreadthFirstSearch(
- mRootNode.get(), [](HitTestingTreeNode* aNode) {
- AsyncPanZoomController* apzc = aNode->GetApzc();
- return (apzc != nullptr);
- });
- return resultNode ? resultNode->GetApzc() : nullptr;
-}
-
// clang-format off
/* The methods GetScreenToApzcTransform() and GetApzcToGeckoTransform() return
some useful transformations that input events may need applied. This is best
@@ -3768,12 +3685,5 @@ float APZCTreeManager::GetDPI() const {
return mDPI;
}
-#if defined(MOZ_WIDGET_ANDROID)
-AndroidDynamicToolbarAnimator*
-APZCTreeManager::GetAndroidDynamicToolbarAnimator() {
- return mToolbarAnimator;
-}
-#endif // defined(MOZ_WIDGET_ANDROID)
-
} // namespace layers
} // namespace mozilla
diff --git a/gfx/layers/apz/src/APZCTreeManager.h b/gfx/layers/apz/src/APZCTreeManager.h
index 3b7639d8c7..5d9ca95e48 100644
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -27,10 +27,6 @@
#include "mozilla/UniquePtr.h" // for UniquePtr
#include "nsCOMPtr.h" // for already_AddRefed
-#if defined(MOZ_WIDGET_ANDROID)
-# include "mozilla/layers/AndroidDynamicToolbarAnimator.h"
-#endif // defined(MOZ_WIDGET_ANDROID)
-
namespace mozilla {
class MultiTouchInput;
@@ -305,14 +301,6 @@ class APZCTreeManager : public IAPZCTreeManager, public APZInputBridge {
#endif
const Maybe& aConstraints) override;
- /**
- * Adjusts the root APZC to compensate for a shift in the surface. See the
- * documentation on AsyncPanZoomController::AdjustScrollForSurfaceShift for
- * some more details. This is only currently needed due to surface shifts
- * caused by the dynamic toolbar on Android.
- */
- void AdjustScrollForSurfaceShift(const ScreenPoint& aShift);
-
/**
* Calls Destroy() on all APZC instances attached to the tree, and resets the
* tree back to empty. This function must be called exactly once during the
@@ -654,19 +642,6 @@ class APZCTreeManager : public IAPZCTreeManager, public APZInputBridge {
Maybe ConvertToGecko(const ScreenIntPoint& aPoint,
AsyncPanZoomController* aApzc);
- /**
- * Process a movement of the dynamic toolbar by |aDeltaY| over the time
- * period from |aStartTimestampMs| to |aEndTimestampMs|.
- * This is used to track velocities accurately in the presence of movement
- * of the dynamic toolbar, since in such cases the finger can be moving
- * relative to the screen even though no scrolling is occurring.
- * Note that this function expects "spatial coordinates" (i.e. toolbar
- * moves up --> negative delta).
- */
- void ProcessDynamicToolbarMovement(uint32_t aStartTimestampMs,
- uint32_t aEndTimestampMs,
- ScreenCoord aDeltaY);
-
/**
* Find the zoomable APZC in the same layer subtree (i.e. with the same
* layers id) as the given APZC.
@@ -706,7 +681,6 @@ class APZCTreeManager : public IAPZCTreeManager, public APZInputBridge {
AsyncPanZoomController* FindRootApzcForLayersId(LayersId aLayersId) const;
AsyncPanZoomController* FindRootContentApzcForLayersId(
LayersId aLayersId) const;
- AsyncPanZoomController* FindRootContentOrRootApzc() const;
already_AddRefed GetZoomableTarget(
AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const;
already_AddRefed CommonAncestor(
@@ -996,11 +970,7 @@ class APZCTreeManager : public IAPZCTreeManager, public APZInputBridge {
float mDPI;
#if defined(MOZ_WIDGET_ANDROID)
- public:
- AndroidDynamicToolbarAnimator* GetAndroidDynamicToolbarAnimator();
-
private:
- RefPtr mToolbarAnimator;
#endif // defined(MOZ_WIDGET_ANDROID)
};
diff --git a/gfx/layers/apz/src/AndroidDynamicToolbarAnimator.cpp b/gfx/layers/apz/src/AndroidDynamicToolbarAnimator.cpp
deleted file mode 100644
index 33eeca0143..0000000000
--- a/gfx/layers/apz/src/AndroidDynamicToolbarAnimator.cpp
+++ /dev/null
@@ -1,1229 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "mozilla/layers/AndroidDynamicToolbarAnimator.h"
-
-#include
-
-#include "APZCTreeManager.h"
-#include "FrameMetrics.h"
-#include "mozilla/EventForwards.h"
-#include "mozilla/FloatingPoint.h"
-#include "mozilla/gfx/2D.h"
-#include "mozilla/gfx/Types.h"
-#include "mozilla/layers/APZThreadUtils.h"
-#include "mozilla/layers/AsyncCompositionManager.h"
-#include "mozilla/layers/CompositorBridgeParent.h"
-#include "mozilla/layers/CompositorOGL.h"
-#include "mozilla/layers/CompositorThread.h"
-#include "mozilla/layers/UiCompositorControllerMessageTypes.h"
-#include "mozilla/layers/UiCompositorControllerParent.h"
-#include "mozilla/MathAlgorithms.h"
-#include "mozilla/Move.h"
-#include "mozilla/StaticPrefs_browser.h"
-#include "mozilla/Unused.h"
-
-namespace {
-
-// Internal flags and constants
-static const float ANIMATION_DURATION =
- 0.15f; // How many seconds the complete animation should span
-static const int32_t MOVE_TOOLBAR_DOWN =
- 1; // Multiplier to move the toolbar down
-static const int32_t MOVE_TOOLBAR_UP = -1; // Multiplier to move the toolbar up
-static const float SHRINK_FACTOR =
- 0.95f; // Amount to shrink the either the full content for small pages or
- // the amount left See: PageTooSmallEnsureToolbarVisible()
-} // namespace
-
-namespace mozilla {
-namespace layers {
-
-AndroidDynamicToolbarAnimator::AndroidDynamicToolbarAnimator(
- APZCTreeManager* aApz)
- : mRootLayerTreeId{0},
- mApz(aApz)
- // Read/Write Compositor Thread, Read only Controller thread
- ,
- mToolbarState(eToolbarVisible),
- mPinnedFlags(0)
- // Controller thread only
- ,
- mControllerScrollingRootContent(false),
- mControllerDragThresholdReached(false),
- mControllerCancelTouchTracking(false),
- mControllerDragChangedDirection(false),
- mControllerResetOnNextMove(false),
- mControllerStartTouch(0),
- mControllerPreviousTouch(0),
- mControllerTotalDistance(0),
- mControllerMaxToolbarHeight(0),
- mControllerToolbarHeight(0),
- mControllerSurfaceHeight(0),
- mControllerCompositionHeight(0),
- mControllerRootScrollY(0.0f),
- mControllerLastDragDirection(0),
- mControllerTouchCount(0),
- mControllerLastEventTimeStamp(0),
- mControllerState(eNothingPending)
- // Compositor thread only
- ,
- mCompositorShutdown(false),
- mCompositorAnimationDeferred(false),
- mCompositorAnimationStarted(false),
- mCompositorReceivedFirstPaint(false),
- mCompositorWaitForPageResize(false),
- mCompositorToolbarShowRequested(false),
- mCompositorSendResponseForSnapshotUpdate(false),
- mCompositorAnimationStyle(eAnimate),
- mCompositorMaxToolbarHeight(0),
- mCompositorToolbarHeight(0),
- mCompositorSurfaceHeight(0),
- mCompositorAnimationDirection(0),
- mCompositorAnimationStartHeight(0) {}
-
-void AndroidDynamicToolbarAnimator::Initialize(LayersId aRootLayerTreeId) {
- MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
- mRootLayerTreeId = aRootLayerTreeId;
- RefPtr uiController =
- UiCompositorControllerParent::GetFromRootLayerTreeId(mRootLayerTreeId);
- MOZ_ASSERT(uiController);
- uiController->RegisterAndroidDynamicToolbarAnimator(this);
-
- // Send queued messages that were posted before Initialize() was called.
- for (QueuedMessage* message = mCompositorQueuedMessages.getFirst();
- message != nullptr; message = message->getNext()) {
- uiController->ToolbarAnimatorMessageFromCompositor(message->mMessage);
- }
- mCompositorQueuedMessages.clear();
-}
-
-void AndroidDynamicToolbarAnimator::ClearTreeManager() {
- MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
- mApz = nullptr;
-}
-
-static bool GetTouchY(MultiTouchInput& multiTouch, ScreenIntCoord* value) {
- MOZ_ASSERT(value);
- if (multiTouch.mTouches.Length() == 1) {
- *value = multiTouch.mTouches[0].mScreenPoint.y;
- return true;
- }
-
- return false;
-}
-
-nsEventStatus AndroidDynamicToolbarAnimator::ReceiveInputEvent(
- const RefPtr& aApz, InputData& aEvent,
- const ScreenPoint& aScrollOffset) {
- MOZ_ASSERT(APZThreadUtils::IsControllerThread());
-
- mControllerRootScrollY = aScrollOffset.y;
-
- // Only process and adjust touch events. Wheel events (aka scroll events) are
- // adjusted in the NativePanZoomController
- if (aEvent.mInputType != MULTITOUCH_INPUT) {
- return nsEventStatus_eIgnore;
- }
-
- MultiTouchInput& multiTouch = aEvent.AsMultiTouchInput();
-
- if (PageTooSmallEnsureToolbarVisible()) {
- TranslateTouchEvent(multiTouch);
- return nsEventStatus_eIgnore;
- }
-
- switch (multiTouch.mType) {
- case MultiTouchInput::MULTITOUCH_START:
- mControllerTouchCount = multiTouch.mTouches.Length();
- break;
- case MultiTouchInput::MULTITOUCH_END:
- case MultiTouchInput::MULTITOUCH_CANCEL:
- mControllerTouchCount -= multiTouch.mTouches.Length();
- break;
- case MultiTouchInput::MULTITOUCH_MOVE:
- break;
- }
-
- if (mControllerTouchCount > 1) {
- mControllerResetOnNextMove = true;
- }
-
- ScreenIntCoord currentTouch = 0;
-
- if (mPinnedFlags || !GetTouchY(multiTouch, ¤tTouch)) {
- TranslateTouchEvent(multiTouch);
- return nsEventStatus_eIgnore;
- }
-
- // Only the return value from ProcessTouchDelta should
- // change status to nsEventStatus_eConsumeNoDefault
- nsEventStatus status = nsEventStatus_eIgnore;
-
- const StaticToolbarState currentToolbarState = mToolbarState;
- switch (multiTouch.mType) {
- case MultiTouchInput::MULTITOUCH_START:
- mControllerCancelTouchTracking = false;
- mControllerStartTouch = mControllerPreviousTouch = currentTouch;
- // We don't want to stop the animation if we are near the bottom of the
- // page.
- if (!ScrollOffsetNearBottom() &&
- (currentToolbarState == eToolbarAnimating)) {
- StopCompositorAnimation();
- }
- break;
- case MultiTouchInput::MULTITOUCH_MOVE: {
- CheckForResetOnNextMove(currentTouch);
- if ((mControllerState != eAnimationStartPending) &&
- (mControllerState != eAnimationStopPending) &&
- (currentToolbarState != eToolbarAnimating) &&
- !mControllerCancelTouchTracking) {
- // Don't move the toolbar if we are near the page bottom
- // and the toolbar is not in transition
- if (ScrollOffsetNearBottom() && !ToolbarInTransition()) {
- ShowToolbarIfNotVisible(currentToolbarState);
- break;
- }
-
- ScreenIntCoord delta = currentTouch - mControllerPreviousTouch;
- mControllerPreviousTouch = currentTouch;
- mControllerTotalDistance += delta;
- if (delta != 0) {
- ScreenIntCoord direction =
- (delta > 0 ? MOVE_TOOLBAR_DOWN : MOVE_TOOLBAR_UP);
- if (mControllerLastDragDirection &&
- (direction != mControllerLastDragDirection)) {
- mControllerDragChangedDirection = true;
- }
- mControllerLastDragDirection = direction;
- }
- // NOTE: StaticPrefs::browser_ui_scroll_toolbar_threshold() returns a
- // percentage as an int32_t. So multiply it by 0.01f to convert.
- const uint32_t dragThreshold = Abs(std::lround(
- 0.01f * StaticPrefs::browser_ui_scroll_toolbar_threshold() *
- mControllerCompositionHeight));
- if ((Abs(mControllerTotalDistance.value) > dragThreshold) &&
- (delta != 0)) {
- mControllerDragThresholdReached = true;
- status = ProcessTouchDelta(aApz, currentToolbarState, delta,
- multiTouch.mTime);
- }
- mControllerLastEventTimeStamp = multiTouch.mTime;
- }
- break;
- }
- case MultiTouchInput::MULTITOUCH_END:
- case MultiTouchInput::MULTITOUCH_CANCEL:
- // last finger was lifted
- if (mControllerTouchCount == 0) {
- HandleTouchEnd(currentToolbarState, currentTouch);
- }
- break;
- }
-
- TranslateTouchEvent(multiTouch);
-
- return status;
-}
-
-void AndroidDynamicToolbarAnimator::SetMaxToolbarHeight(
- ScreenIntCoord aHeight) {
- MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
- UpdateControllerToolbarHeight(aHeight, aHeight);
- mCompositorMaxToolbarHeight = aHeight;
- UpdateCompositorToolbarHeight(aHeight);
-}
-
-void AndroidDynamicToolbarAnimator::SetPinned(bool aPinned, int32_t aReason) {
- MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
- MOZ_ASSERT(aReason < 32);
- uint32_t bit = 0x01 << aReason;
- uint32_t current = mPinnedFlags;
- if (aPinned) {
- mPinnedFlags = current | bit;
- } else {
- mPinnedFlags = current & (~bit);
- }
-}
-
-ScreenIntCoord AndroidDynamicToolbarAnimator::GetMaxToolbarHeight() const {
- MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
- return mCompositorMaxToolbarHeight;
-}
-
-ScreenIntCoord AndroidDynamicToolbarAnimator::GetCurrentToolbarHeight() const {
- MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
- return mCompositorToolbarHeight;
-}
-
-ScreenIntCoord AndroidDynamicToolbarAnimator::GetCurrentContentOffset() const {
- MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
- if (mCompositorAnimationStarted && (mToolbarState == eToolbarAnimating)) {
- return 0;
- }
-
- return mCompositorToolbarHeight;
-}
-
-ScreenIntCoord AndroidDynamicToolbarAnimator::GetCurrentSurfaceHeight() const {
- MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
- return mCompositorSurfaceHeight;
-}
-
-ScreenIntCoord AndroidDynamicToolbarAnimator::GetCompositionHeight() const {
- MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
- return mCompositorCompositionSize.height;
-}
-
-void AndroidDynamicToolbarAnimator::SetScrollingRootContent() {
- MOZ_ASSERT(APZThreadUtils::IsControllerThread());
- mControllerScrollingRootContent = true;
-}
-
-void AndroidDynamicToolbarAnimator::ToolbarAnimatorMessageFromUI(
- int32_t aMessage) {
- MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
- switch (aMessage) {
- case STATIC_TOOLBAR_NEEDS_UPDATE:
- break;
- case STATIC_TOOLBAR_READY:
- break;
- case TOOLBAR_HIDDEN:
- // If the toolbar is animating, then it is already unlocked.
- if (mToolbarState != eToolbarAnimating) {
- mToolbarState = eToolbarUnlocked;
- if (mCompositorAnimationDeferred) {
- StartCompositorAnimation(
- mCompositorAnimationDirection, mCompositorAnimationStyle,
- mCompositorToolbarHeight, mCompositorWaitForPageResize);
- }
- } else {
- // Animation already running so just make sure it is going the right
- // direction.
- StartCompositorAnimation(MOVE_TOOLBAR_UP, mCompositorAnimationStyle,
- mCompositorToolbarHeight,
- mCompositorWaitForPageResize);
- }
- break;
- case TOOLBAR_VISIBLE:
- // If we are currently animating, let the animation finish.
- if (mToolbarState != eToolbarAnimating) {
- mToolbarState = eToolbarVisible;
- }
- break;
- case TOOLBAR_SHOW:
- break;
- case FIRST_PAINT:
- break;
- case REQUEST_SHOW_TOOLBAR_IMMEDIATELY:
- NotifyControllerPendingAnimation(MOVE_TOOLBAR_DOWN, eImmediate);
- break;
- case REQUEST_SHOW_TOOLBAR_ANIMATED:
- NotifyControllerPendingAnimation(MOVE_TOOLBAR_DOWN, eAnimate);
- break;
- case REQUEST_HIDE_TOOLBAR_IMMEDIATELY:
- NotifyControllerPendingAnimation(MOVE_TOOLBAR_UP, eImmediate);
- break;
- case REQUEST_HIDE_TOOLBAR_ANIMATED:
- NotifyControllerPendingAnimation(MOVE_TOOLBAR_UP, eAnimate);
- break;
- case TOOLBAR_SNAPSHOT_FAILED:
- mToolbarState = eToolbarVisible;
- NotifyControllerSnapshotFailed();
- break;
- default:
- break;
- }
-}
-
-bool AndroidDynamicToolbarAnimator::UpdateAnimation(
- const TimeStamp& aCurrentFrame) {
- MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
- if ((mToolbarState != eToolbarAnimating) || mCompositorShutdown) {
- return false;
- }
-
- CompositorBridgeParent* parent =
- CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(
- mRootLayerTreeId);
- if (!parent) {
- return false;
- }
- MOZ_ASSERT(mApz); // because parent is non-null
-
- AsyncCompositionManager* manager = parent->GetCompositionManager(nullptr);
- if (!manager) {
- return false;
- }
-
- if (mCompositorSurfaceHeight != mCompositorCompositionSize.height) {
- // Waiting for the composition to resize
- if (mCompositorWaitForPageResize && mCompositorAnimationStarted) {
- mCompositorWaitForPageResize = false;
- } else {
- return true;
- }
- } else if (!mCompositorAnimationStarted) {
- mApz->AdjustScrollForSurfaceShift(
- ScreenPoint(0.0f, (float)(-mCompositorToolbarHeight)));
- manager->SetFixedLayerMargins(mCompositorToolbarHeight, 0);
- mCompositorAnimationStarted = true;
- mCompositorReceivedFirstPaint = false;
- mCompositorToolbarShowRequested = false;
- // Reset the start time so the toolbar does not jump on the first animation
- // frame
- mCompositorAnimationStartTimeStamp = aCurrentFrame;
- // Since the delta time for this frame will be zero. Just return, the
- // animation will start on the next frame.
- return true;
- }
-
- bool continueAnimating = true;
-
- if (mCompositorAnimationStyle == eImmediate) {
- if (mCompositorAnimationDirection == MOVE_TOOLBAR_DOWN) {
- mCompositorToolbarHeight = mCompositorMaxToolbarHeight;
- } else if (mCompositorAnimationDirection == MOVE_TOOLBAR_UP) {
- mCompositorToolbarHeight = 0;
- }
- } else if (mCompositorAnimationStyle == eAnimate) {
- const float rate =
- ((float)mCompositorMaxToolbarHeight) / ANIMATION_DURATION;
- float deltaTime =
- (aCurrentFrame - mCompositorAnimationStartTimeStamp).ToSeconds();
- // This animation was started in the future!
- if (deltaTime < 0.0f) {
- deltaTime = 0.0f;
- }
- mCompositorToolbarHeight =
- mCompositorAnimationStartHeight +
- ((int32_t)(rate * deltaTime) * mCompositorAnimationDirection);
- }
-
- if ((mCompositorAnimationDirection == MOVE_TOOLBAR_DOWN) &&
- (mCompositorToolbarHeight >= mCompositorMaxToolbarHeight)) {
- // if the toolbar is being animated and the page is at the end, the
- // animation needs to wait for the page to resize before ending the
- // animation so that the page may be scrolled
- if (!mCompositorReceivedFirstPaint && mCompositorWaitForPageResize) {
- continueAnimating = true;
- } else {
- continueAnimating = false;
- mToolbarState = eToolbarVisible;
- }
- // Make sure we only send one show request per animation
- if (!mCompositorToolbarShowRequested) {
- PostMessage(TOOLBAR_SHOW);
- mCompositorToolbarShowRequested = true;
- }
- mCompositorToolbarHeight = mCompositorMaxToolbarHeight;
- } else if ((mCompositorAnimationDirection == MOVE_TOOLBAR_UP) &&
- (mCompositorToolbarHeight <= 0)) {
- continueAnimating = false;
- mToolbarState = eToolbarUnlocked;
- mCompositorToolbarHeight = 0;
- }
-
- if (continueAnimating) {
- manager->SetFixedLayerMargins(mCompositorToolbarHeight, 0);
- } else {
- if (mCompositorAnimationDirection == MOVE_TOOLBAR_DOWN) {
- if (!mCompositorReceivedFirstPaint) {
- mApz->AdjustScrollForSurfaceShift(
- ScreenPoint(0.0f, (float)mCompositorMaxToolbarHeight));
- }
- manager->SetFixedLayerMargins(0, GetFixedLayerMarginsBottom());
- } else {
- manager->SetFixedLayerMargins(0, 0);
- }
- }
-
- if (!continueAnimating) {
- NotifyControllerAnimationStopped(mCompositorToolbarHeight);
- } else {
- UpdateControllerToolbarHeight(mCompositorToolbarHeight);
- }
-
- return continueAnimating;
-}
-
-void AndroidDynamicToolbarAnimator::FirstPaint() {
- MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
- mCompositorReceivedFirstPaint = true;
-}
-
-void AndroidDynamicToolbarAnimator::UpdateRootFrameMetrics(
- const FrameMetrics& aMetrics) {
- CSSToScreenScale scale = ViewTargetAs(
- aMetrics.GetZoom().ToScaleFactor(),
- PixelCastJustification::ScreenIsParentLayerForRoot);
- ScreenPoint scrollOffset = aMetrics.GetScrollOffset() * scale;
- CSSRect cssPageRect = aMetrics.GetScrollableRect();
-
- UpdateFrameMetrics(scrollOffset, scale, cssPageRect);
-}
-
-void AndroidDynamicToolbarAnimator::
- MaybeUpdateCompositionSizeAndRootFrameMetrics(
- const FrameMetrics& aMetrics) {
- MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
- CSSToScreenScale scale = ViewTargetAs(
- aMetrics.GetZoom().ToScaleFactor(),
- PixelCastJustification::ScreenIsParentLayerForRoot);
- ScreenIntSize size =
- ScreenIntSize::Round(aMetrics.GetRootCompositionSize() * scale);
-
- if (mCompositorCompositionSize == size) {
- return;
- }
-
- ScreenIntSize prevSize = mCompositorCompositionSize;
- mCompositorCompositionSize = size;
-
- // The width has changed so the static snapshot needs to be updated
- if ((prevSize.width != size.width) && (mToolbarState == eToolbarUnlocked)) {
- // No need to set mCompositorSendResponseForSnapshotUpdate. If it is already
- // true we don't want to change it.
- PostMessage(STATIC_TOOLBAR_NEEDS_UPDATE);
- }
-
- if (prevSize.height != size.height) {
- UpdateControllerCompositionHeight(size.height);
- UpdateFixedLayerMargins();
- }
-
- UpdateRootFrameMetrics(aMetrics);
-}
-
-void AndroidDynamicToolbarAnimator::AdoptToolbarPixels(
- mozilla::ipc::Shmem&& aMem, const ScreenIntSize& aSize) {
- MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
- mCompositorToolbarPixels = Some(std::move(aMem));
- mCompositorToolbarPixelsSize = aSize;
-}
-
-void AndroidDynamicToolbarAnimator::UpdateToolbarSnapshotTexture(
- CompositorOGL* gl) {
- MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
- // if the compositor has shutdown, do not create any new rendering objects.
- if (mCompositorShutdown) {
- return;
- }
-
- if (mCompositorToolbarPixels) {
- RefPtr surface =
- gfx::Factory::CreateWrappingDataSourceSurface(
- mCompositorToolbarPixels.ref().get(),
- mCompositorToolbarPixelsSize.width * 4,
- gfx::IntSize(mCompositorToolbarPixelsSize.width,
- mCompositorToolbarPixelsSize.height),
- gfx::SurfaceFormat::B8G8R8A8);
-
- if (!mCompositorToolbarTexture) {
- mCompositorToolbarTexture = gl->CreateDataTextureSource();
- mCompositorToolbarEffect = nullptr;
- }
-
- if (!mCompositorToolbarTexture->Update(surface)) {
- // Upload failed!
- mCompositorToolbarTexture = nullptr;
- }
-
- RefPtr uiController =
- UiCompositorControllerParent::GetFromRootLayerTreeId(mRootLayerTreeId);
- uiController->DeallocShmem(mCompositorToolbarPixels.ref());
- mCompositorToolbarPixels.reset();
- // Send notification that texture is ready after the current composition has
- // completed.
- if (mCompositorToolbarTexture && mCompositorSendResponseForSnapshotUpdate) {
- mCompositorSendResponseForSnapshotUpdate = false;
- CompositorThreadHolder::Loop()->PostTask(NewRunnableMethod(
- "AndroidDynamicToolbarAnimator::PostToolbarReady", this,
- &AndroidDynamicToolbarAnimator::PostToolbarReady));
- }
- }
-}
-
-Effect* AndroidDynamicToolbarAnimator::GetToolbarEffect() {
- MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
- // if the compositor has shutdown, do not create any new rendering objects.
- if (mCompositorShutdown) {
- return nullptr;
- }
-
- if (mCompositorToolbarTexture) {
- if (!mCompositorToolbarEffect) {
- mCompositorToolbarEffect = new EffectRGB(mCompositorToolbarTexture, true,
- gfx::SamplingFilter::LINEAR);
- }
-
- float ratioVisible =
- (float)mCompositorToolbarHeight / (float)mCompositorMaxToolbarHeight;
- mCompositorToolbarEffect->mTextureCoords.y = 1.0f - ratioVisible;
- mCompositorToolbarEffect->mTextureCoords.height = ratioVisible;
- }
-
- return mCompositorToolbarEffect.get();
-}
-
-void AndroidDynamicToolbarAnimator::Shutdown() {
- MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
- mCompositorShutdown = true;
- mCompositorToolbarEffect = nullptr;
- mCompositorToolbarTexture = nullptr;
- mCompositorQueuedMessages.clear();
- if (mCompositorToolbarPixels) {
- RefPtr uiController =
- UiCompositorControllerParent::GetFromRootLayerTreeId(mRootLayerTreeId);
- uiController->DeallocShmem(mCompositorToolbarPixels.ref());
- mCompositorToolbarPixels.reset();
- }
-}
-
-nsEventStatus AndroidDynamicToolbarAnimator::ProcessTouchDelta(
- const RefPtr& aApz,
- StaticToolbarState aCurrentToolbarState, ScreenIntCoord aDelta,
- uint32_t aTimeStamp) {
- MOZ_ASSERT(APZThreadUtils::IsControllerThread());
- MOZ_ASSERT(aApz);
- nsEventStatus status = nsEventStatus_eIgnore;
-
- const bool tryingToHideToolbar = aDelta < 0;
-
- if (tryingToHideToolbar && !mControllerScrollingRootContent) {
- // This prevent the toolbar from hiding if a subframe is being scrolled up.
- // The toolbar will always become visible regardless what is being scrolled
- // down.
- return status;
- }
-
- if (aCurrentToolbarState == eToolbarVisible) {
- if (tryingToHideToolbar && (mControllerState != eUnlockPending)) {
- mCompositorSendResponseForSnapshotUpdate = true;
- PostMessage(STATIC_TOOLBAR_NEEDS_UPDATE);
- mControllerState = eUnlockPending;
- }
- return status;
- }
-
- if (aCurrentToolbarState != eToolbarUnlocked) {
- return status;
- }
-
- if ((mControllerState != eUnlockPending) &&
- (mControllerState != eNothingPending)) {
- return status;
- }
-
- mControllerState = eNothingPending;
- if ((tryingToHideToolbar && (mControllerToolbarHeight > 0)) ||
- (!tryingToHideToolbar &&
- (mControllerToolbarHeight < mControllerMaxToolbarHeight))) {
- ScreenIntCoord deltaRemainder = 0;
- mControllerToolbarHeight += aDelta;
- if (tryingToHideToolbar && (mControllerToolbarHeight <= 0)) {
- deltaRemainder = mControllerToolbarHeight;
- mControllerToolbarHeight = 0;
- } else if (!tryingToHideToolbar &&
- (mControllerToolbarHeight >= mControllerMaxToolbarHeight)) {
- deltaRemainder = mControllerToolbarHeight - mControllerMaxToolbarHeight;
- mControllerToolbarHeight = mControllerMaxToolbarHeight;
- mControllerState = eShowPending;
- PostMessage(TOOLBAR_SHOW);
- }
-
- UpdateCompositorToolbarHeight(mControllerToolbarHeight);
- RequestComposite();
- // If there was no delta left over, the event was completely consumed.
- if (deltaRemainder == 0) {
- status = nsEventStatus_eConsumeNoDefault;
- }
-
- uint32_t timeDelta = aTimeStamp - mControllerLastEventTimeStamp;
- if (mControllerLastEventTimeStamp && timeDelta && aDelta) {
- // we can't use mApz because we're on the controller thread, so we have
- // the caller provide a RefPtr to the same underlying object, which should
- // be safe to use.
- aApz->ProcessDynamicToolbarMovement(mControllerLastEventTimeStamp,
- aTimeStamp, (float)aDelta);
- }
- }
-
- return status;
-}
-
-void AndroidDynamicToolbarAnimator::HandleTouchEnd(
- StaticToolbarState aCurrentToolbarState, ScreenIntCoord aCurrentTouch) {
- MOZ_ASSERT(APZThreadUtils::IsControllerThread());
- // If there was no move before the reset flag was set and the touch ended,
- // check for it here. if mControllerResetOnNextMove is true, it will be set to
- // false here
- CheckForResetOnNextMove(aCurrentTouch);
- int32_t direction = mControllerLastDragDirection;
- mControllerLastDragDirection = 0;
- bool isRoot = mControllerScrollingRootContent;
- mControllerScrollingRootContent = false;
- bool dragChangedDirection = mControllerDragChangedDirection;
- mControllerDragChangedDirection = false;
-
- // If the drag direction changed and the toolbar is partially visible, hide in
- // the direction with the least distance to travel.
- if (dragChangedDirection && ToolbarInTransition()) {
- direction = ((float)mControllerToolbarHeight /
- (float)mControllerMaxToolbarHeight) < 0.5f
- ? MOVE_TOOLBAR_UP
- : MOVE_TOOLBAR_DOWN;
- }
-
- // If the last touch didn't have a drag direction, use start of touch to find
- // direction
- if (!direction) {
- if (mControllerToolbarHeight == mControllerMaxToolbarHeight) {
- direction = MOVE_TOOLBAR_DOWN;
- } else if (mControllerToolbarHeight == 0) {
- direction = MOVE_TOOLBAR_UP;
- } else {
- direction =
- ((aCurrentTouch - mControllerStartTouch) > 0 ? MOVE_TOOLBAR_DOWN
- : MOVE_TOOLBAR_UP);
- }
- // If there still isn't a direction, default to show just to be safe
- if (!direction) {
- direction = MOVE_TOOLBAR_DOWN;
- }
- }
- mControllerStartTouch = 0;
- mControllerPreviousTouch = 0;
- mControllerTotalDistance = 0;
- bool dragThresholdReached = mControllerDragThresholdReached;
- mControllerDragThresholdReached = false;
- mControllerLastEventTimeStamp = 0;
- bool cancelTouchTracking = mControllerCancelTouchTracking;
- mControllerCancelTouchTracking = false;
-
- // Animation is in progress, bail out.
- if (aCurrentToolbarState == eToolbarAnimating) {
- return;
- }
-
- // Received a UI thread request to show or hide the snapshot during a touch.
- // This overrides the touch event so just return.
- if (cancelTouchTracking) {
- return;
- }
-
- // The drag threshold has not been reach and the toolbar is either completely
- // visible or completely hidden.
- if (!dragThresholdReached && !ToolbarInTransition()) {
- ShowToolbarIfNotVisible(aCurrentToolbarState);
- return;
- }
-
- // The toolbar is already where it needs to be so just return.
- if (((direction == MOVE_TOOLBAR_DOWN) &&
- (mControllerToolbarHeight == mControllerMaxToolbarHeight)) ||
- ((direction == MOVE_TOOLBAR_UP) && (mControllerToolbarHeight == 0))) {
- ShowToolbarIfNotVisible(aCurrentToolbarState);
- return;
- }
-
- // Don't animate up if not scrolling root content. Even though
- // ShowToolbarIfNotVisible checks if snapshot toolbar is completely visible
- // before showing, we don't want to enter this if block if the snapshot
- // toolbar isn't completely visible to avoid early return.
- if (!isRoot && ((direction == MOVE_TOOLBAR_UP) &&
- (mControllerToolbarHeight == mControllerMaxToolbarHeight))) {
- ShowToolbarIfNotVisible(aCurrentToolbarState);
- return;
- }
-
- if (ScrollOffsetNearBottom()) {
- if (ToolbarInTransition()) {
- // Toolbar is partially visible so make it visible since we are near the
- // end of the page
- direction = MOVE_TOOLBAR_DOWN;
- } else {
- // Don't start an animation if near the bottom of page and toolbar is
- // completely visible or hidden
- ShowToolbarIfNotVisible(aCurrentToolbarState);
- return;
- }
- }
-
- StartCompositorAnimation(direction, eAnimate, mControllerToolbarHeight,
- ScrollOffsetNearBottom());
-}
-
-void AndroidDynamicToolbarAnimator::PostMessage(int32_t aMessage) {
- // if the root layer tree id is zero then Initialize() has not been called yet
- // so queue the message until Initialize() is called.
- if (!mRootLayerTreeId.IsValid()) {
- QueueMessage(aMessage);
- return;
- }
-
- RefPtr uiController =
- UiCompositorControllerParent::GetFromRootLayerTreeId(mRootLayerTreeId);
- if (!uiController) {
- // Looks like IPC may be shutdown.
- return;
- }
-
- // ToolbarAnimatorMessageFromCompositor may be called from any thread.
- uiController->ToolbarAnimatorMessageFromCompositor(aMessage);
-}
-
-void AndroidDynamicToolbarAnimator::UpdateCompositorToolbarHeight(
- ScreenIntCoord aHeight) {
- if (!CompositorThreadHolder::IsInCompositorThread()) {
- CompositorThreadHolder::Loop()->PostTask(NewRunnableMethod(
- "AndroidDynamicToolbarAnimator::UpdateCompositorToolbarHeight", this,
- &AndroidDynamicToolbarAnimator::UpdateCompositorToolbarHeight,
- aHeight));
- return;
- }
-
- mCompositorToolbarHeight = aHeight;
- UpdateFixedLayerMargins();
-}
-
-void AndroidDynamicToolbarAnimator::UpdateControllerToolbarHeight(
- ScreenIntCoord aHeight, ScreenIntCoord aMaxHeight) {
- if (!APZThreadUtils::IsControllerThread()) {
- APZThreadUtils::RunOnControllerThread(
- NewRunnableMethod(
- "AndroidDynamicToolbarAnimator::UpdateControllerToolbarHeight",
- this, &AndroidDynamicToolbarAnimator::UpdateControllerToolbarHeight,
- aHeight, aMaxHeight));
- return;
- }
-
- mControllerToolbarHeight = aHeight;
- if (aMaxHeight >= 0) {
- mControllerMaxToolbarHeight = aMaxHeight;
- }
-}
-
-void AndroidDynamicToolbarAnimator::UpdateControllerSurfaceHeight(
- ScreenIntCoord aHeight) {
- if (!APZThreadUtils::IsControllerThread()) {
- APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
- "AndroidDynamicToolbarAnimator::UpdateControllerSurfaceHeight", this,
- &AndroidDynamicToolbarAnimator::UpdateControllerSurfaceHeight,
- aHeight));
- return;
- }
-
- mControllerSurfaceHeight = aHeight;
-}
-
-void AndroidDynamicToolbarAnimator::UpdateControllerCompositionHeight(
- ScreenIntCoord aHeight) {
- if (!APZThreadUtils::IsControllerThread()) {
- APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
- "AndroidDynamicToolbarAnimator::UpdateControllerCompositionHeight",
- this, &AndroidDynamicToolbarAnimator::UpdateControllerCompositionHeight,
- aHeight));
- return;
- }
-
- mControllerCompositionHeight = aHeight;
-}
-
-// Ensures the margin for the fixed layers match the position of the toolbar
-void AndroidDynamicToolbarAnimator::UpdateFixedLayerMargins() {
- MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
- if (mCompositorShutdown) {
- return;
- }
- CompositorBridgeParent* parent =
- CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(
- mRootLayerTreeId);
- if (parent) {
- ScreenIntCoord surfaceHeight = parent->GetEGLSurfaceSize().height;
- if (surfaceHeight != mCompositorSurfaceHeight) {
- mCompositorSurfaceHeight = surfaceHeight;
- UpdateControllerSurfaceHeight(mCompositorSurfaceHeight);
- }
- AsyncCompositionManager* manager = parent->GetCompositionManager(nullptr);
- if (manager) {
- if ((mToolbarState == eToolbarAnimating) && mCompositorAnimationStarted) {
- manager->SetFixedLayerMargins(mCompositorToolbarHeight, 0);
- } else {
- manager->SetFixedLayerMargins(0, GetFixedLayerMarginsBottom());
- }
- }
- }
-}
-
-void AndroidDynamicToolbarAnimator::NotifyControllerPendingAnimation(
- int32_t aDirection, AnimationStyle aAnimationStyle) {
- if (!APZThreadUtils::IsControllerThread()) {
- APZThreadUtils::RunOnControllerThread(
- NewRunnableMethod(
- "AndroidDynamicToolbarAnimator::NotifyControllerPendingAnimation",
- this,
- &AndroidDynamicToolbarAnimator::NotifyControllerPendingAnimation,
- aDirection, aAnimationStyle));
- return;
- }
-
- mControllerCancelTouchTracking = true;
-
- // If the toolbar is already where it needs to be, just abort the request.
- if (((mControllerToolbarHeight == mControllerMaxToolbarHeight) &&
- (aDirection == MOVE_TOOLBAR_DOWN)) ||
- ((mControllerToolbarHeight == 0) && (aDirection == MOVE_TOOLBAR_UP))) {
- // We received a show request but the real toolbar is hidden, so tell it to
- // show now.
- if ((aDirection == MOVE_TOOLBAR_DOWN) &&
- (mToolbarState == eToolbarUnlocked)) {
- PostMessage(TOOLBAR_SHOW);
- }
- return;
- }
-
- // NOTE: StartCompositorAnimation will set mControllerState to
- // eAnimationStartPending
- StartCompositorAnimation(aDirection, aAnimationStyle,
- mControllerToolbarHeight, ScrollOffsetNearBottom());
- MOZ_ASSERT(mControllerState == eAnimationStartPending);
-}
-
-void AndroidDynamicToolbarAnimator::StartCompositorAnimation(
- int32_t aDirection, AnimationStyle aAnimationStyle, ScreenIntCoord aHeight,
- bool aWaitForPageResize) {
- if (!CompositorThreadHolder::IsInCompositorThread()) {
- mControllerState = eAnimationStartPending;
- CompositorThreadHolder::Loop()->PostTask(
- NewRunnableMethod(
- "AndroidDynamicToolbarAnimator::StartCompositorAnimation", this,
- &AndroidDynamicToolbarAnimator::StartCompositorAnimation,
- aDirection, aAnimationStyle, aHeight, aWaitForPageResize));
- return;
- }
-
- MOZ_ASSERT(aDirection == MOVE_TOOLBAR_UP || aDirection == MOVE_TOOLBAR_DOWN);
-
- const StaticToolbarState initialToolbarState = mToolbarState;
- mCompositorAnimationDirection = aDirection;
- mCompositorAnimationStartHeight = mCompositorToolbarHeight = aHeight;
- mCompositorAnimationStyle = aAnimationStyle;
- mCompositorWaitForPageResize = aWaitForPageResize;
- // If the snapshot is not unlocked, request the UI thread update the snapshot
- // and defer animation until it has been unlocked
- if ((initialToolbarState != eToolbarUnlocked) &&
- (initialToolbarState != eToolbarAnimating)) {
- mCompositorAnimationDeferred = true;
- mCompositorSendResponseForSnapshotUpdate = true;
- PostMessage(STATIC_TOOLBAR_NEEDS_UPDATE);
- } else {
- // Toolbar is either unlocked or already animating so animation may begin
- // immediately
- mCompositorAnimationDeferred = false;
- mToolbarState = eToolbarAnimating;
- if (initialToolbarState != eToolbarAnimating) {
- mCompositorAnimationStarted = false;
- }
- // Let the controller know we are starting an animation so it may clear the
- // AnimationStartPending flag.
- NotifyControllerAnimationStarted();
- // Only reset the time stamp and start compositor animation if not already
- // animating.
- if (initialToolbarState != eToolbarAnimating) {
- if (mApz) {
- mCompositorAnimationStartTimeStamp = mApz->GetFrameTime();
- }
- // Kick the compositor to start the animation if we aren't already
- // animating.
- RequestComposite();
- }
- }
-}
-
-void AndroidDynamicToolbarAnimator::NotifyControllerAnimationStarted() {
- if (!APZThreadUtils::IsControllerThread()) {
- APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
- "AndroidDynamicToolbarAnimator::NotifyControllerAnimationStarted", this,
- &AndroidDynamicToolbarAnimator::NotifyControllerAnimationStarted));
- return;
- }
-
- // It is possible there was a stop request after the start request so only set
- // to NothingPending if start is what were are still waiting for.
- if (mControllerState == eAnimationStartPending) {
- mControllerState = eNothingPending;
- }
-}
-
-void AndroidDynamicToolbarAnimator::StopCompositorAnimation() {
- if (!CompositorThreadHolder::IsInCompositorThread()) {
- mControllerState = eAnimationStopPending;
- CompositorThreadHolder::Loop()->PostTask(NewRunnableMethod(
- "AndroidDynamicToolbarAnimator::StopCompositorAnimation", this,
- &AndroidDynamicToolbarAnimator::StopCompositorAnimation));
- return;
- }
-
- if (mToolbarState == eToolbarAnimating) {
- if (mCompositorAnimationStarted) {
- mCompositorAnimationStarted = false;
- CompositorBridgeParent* parent =
- CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(
- mRootLayerTreeId);
- if (parent) {
- AsyncCompositionManager* manager =
- parent->GetCompositionManager(nullptr);
- if (manager) {
- MOZ_ASSERT(mApz);
- mApz->AdjustScrollForSurfaceShift(
- ScreenPoint(0.0f, (float)(mCompositorToolbarHeight)));
- RequestComposite();
- }
- }
- }
- mToolbarState = eToolbarUnlocked;
- }
-
- NotifyControllerAnimationStopped(mCompositorToolbarHeight);
-}
-
-void AndroidDynamicToolbarAnimator::NotifyControllerAnimationStopped(
- ScreenIntCoord aHeight) {
- if (!APZThreadUtils::IsControllerThread()) {
- APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
- "AndroidDynamicToolbarAnimator::NotifyControllerAnimationStopped", this,
- &AndroidDynamicToolbarAnimator::NotifyControllerAnimationStopped,
- aHeight));
- return;
- }
-
- if (mControllerState == eAnimationStopPending) {
- mControllerState = eNothingPending;
- }
-
- mControllerToolbarHeight = aHeight;
- RequestComposite();
-}
-
-void AndroidDynamicToolbarAnimator::RequestComposite() {
- if (!CompositorThreadHolder::IsInCompositorThread()) {
- CompositorThreadHolder::Loop()->PostTask(NewRunnableMethod(
- "AndroidDynamicToolbarAnimator::RequestComposite", this,
- &AndroidDynamicToolbarAnimator::RequestComposite));
- return;
- }
-
- if (mCompositorShutdown) {
- return;
- }
-
- CompositorBridgeParent* parent =
- CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(
- mRootLayerTreeId);
- if (parent) {
- AsyncCompositionManager* manager = parent->GetCompositionManager(nullptr);
- if (manager) {
- if ((mToolbarState == eToolbarAnimating) && mCompositorAnimationStarted) {
- manager->SetFixedLayerMargins(mCompositorToolbarHeight, 0);
- } else {
- manager->SetFixedLayerMargins(0, GetFixedLayerMarginsBottom());
- }
- parent->Invalidate();
- parent->ScheduleComposition();
- }
- }
-}
-
-void AndroidDynamicToolbarAnimator::PostToolbarReady() {
- MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
- RequestComposite();
- // Notify the UI thread the static toolbar is being rendered so the real
- // toolbar needs to be hidden. Once the TOOLBAR_HIDDEN message is
- // received, a pending animation may start or the toolbar snapshot may be
- // translated.
- PostMessage(STATIC_TOOLBAR_READY);
- if (mToolbarState != eToolbarAnimating) {
- mToolbarState = eToolbarUpdated;
- } else {
- // The compositor is already animating the toolbar so no need to defer.
- mCompositorAnimationDeferred = false;
- }
-}
-
-void AndroidDynamicToolbarAnimator::UpdateFrameMetrics(
- ScreenPoint aScrollOffset, CSSToScreenScale aScale, CSSRect aCssPageRect) {
- if (!APZThreadUtils::IsControllerThread()) {
- APZThreadUtils::RunOnControllerThread(
- NewRunnableMethod(
- "AndroidDynamicToolbarAnimator::UpdateFrameMetrics", this,
- &AndroidDynamicToolbarAnimator::UpdateFrameMetrics, aScrollOffset,
- aScale, aCssPageRect));
- return;
- }
-
- mControllerRootScrollY = aScrollOffset.y;
-
- if (mControllerFrameMetrics.Update(aScrollOffset, aScale, aCssPageRect)) {
- if (FuzzyEqualsMultiplicative(
- mControllerFrameMetrics.mPageRect.YMost(),
- mControllerCompositionHeight +
- mControllerFrameMetrics.mScrollOffset.y) &&
- (mControllerFrameMetrics.mPageRect.YMost() >
- (mControllerSurfaceHeight * 2)) &&
- (mControllerToolbarHeight != mControllerMaxToolbarHeight) &&
- !mPinnedFlags) {
- // The end of the page has been reached, the page is twice the height of
- // the visible height, and the toolbar is not completely visible so
- // animate it into view.
- StartCompositorAnimation(MOVE_TOOLBAR_DOWN, eAnimate,
- mControllerToolbarHeight,
- /* wait for page resize */ true);
- }
- RefPtr uiController =
- UiCompositorControllerParent::GetFromRootLayerTreeId(mRootLayerTreeId);
- MOZ_ASSERT(uiController);
- CompositorThreadHolder::Loop()->PostTask(
- NewRunnableMethod