diff --git a/gfx/thebes/gfxUtils.h b/gfx/thebes/gfxUtils.h index a1854cbbcd9d..7ae420c25091 100644 --- a/gfx/thebes/gfxUtils.h +++ b/gfx/thebes/gfxUtils.h @@ -419,7 +419,8 @@ namespace mozilla { // Container for either a single element of type T, or an nsTArray. // Provides a minimal subset of nsTArray's API, just enough to support use -// by ContextState for the clipsAndTransforms list. +// by ContextState for the clipsAndTransforms list, and by gfxTextRun for +// its mGlyphRuns. // Using this instead of a simple nsTArray avoids an extra allocation in the // common case where no more than one element is ever added to the list. // Unlike an AutoTArray<..., 1>, this class is memmovable and therefore can @@ -435,6 +436,13 @@ class ElementOrArray { Array, } mTag; + // gfxTextRun::SortGlyphRuns and SanitizeGlyphRuns directly access the array. + friend class gfxTextRun; + nsTArray& Array() { + MOZ_DIAGNOSTIC_ASSERT(mTag == Tag::Array); + return mArray; + } + public: // Construct as an empty array. ElementOrArray() : mTag(Tag::Array) { new (&mArray) nsTArray(); } @@ -499,6 +507,55 @@ class ElementOrArray { return mTag == Tag::Element ? false : mArray.IsEmpty(); } + void TruncateLength(uint32_t aLength = 0) { + MOZ_DIAGNOSTIC_ASSERT(aLength <= Length()); + switch (mTag) { + case Tag::Element: + if (aLength == 0) { + // Destroy the single element, and convert to an empty array. + mElement.~T(); + mTag = Tag::Array; + new (&mArray) nsTArray(); + } + break; + case Tag::Array: + mArray.TruncateLength(aLength); + break; + } + } + + void Clear() { + switch (mTag) { + case Tag::Element: + mElement.~T(); + mTag = Tag::Array; + new (&mArray) nsTArray(); + break; + case Tag::Array: + mArray.Clear(); + break; + } + } + + // Convert from Array to Element storage. Only to be used when the current + // state is a single-element array! + void ConvertToElement() { + MOZ_DIAGNOSTIC_ASSERT(mTag == Tag::Array && mArray.Length() == 1); + T temp = std::move(mArray[0]); + mArray.~nsTArray(); + mTag = Tag::Element; + new (&mElement) T(std::move(temp)); + } + + const T& operator[](uint32_t aIndex) const { + MOZ_DIAGNOSTIC_ASSERT(aIndex < Length()); + return mTag == Tag::Element ? mElement : mArray[aIndex]; + } + T& operator[](uint32_t aIndex) { + MOZ_DIAGNOSTIC_ASSERT(aIndex < Length()); + return mTag == Tag::Element ? mElement : mArray[aIndex]; + } + // Simple iterators to support range-for loops. const T* begin() const { return mTag == Tag::Array ? mArray.IsEmpty() ? nullptr : &*mArray.begin() @@ -515,6 +572,11 @@ class ElementOrArray { T* end() { return mTag == Tag::Array ? begin() + mArray.Length() : &mElement + 1; } + + size_t ShallowSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) { + return mTag == Tag::Array ? mArray.ShallowSizeOfExcludingThis(aMallocSizeOf) + : 0; + } }; struct StyleAbsoluteColor;