diff --git a/gfx/layers/wr/IpcResourceUpdateQueue.cpp b/gfx/layers/wr/IpcResourceUpdateQueue.cpp index e6cc5f3c3b0b..01b6d18cdbb0 100644 --- a/gfx/layers/wr/IpcResourceUpdateQueue.cpp +++ b/gfx/layers/wr/IpcResourceUpdateQueue.cpp @@ -230,15 +230,12 @@ bool ShmSegmentsReader::Read(const layers::OffsetRange& aRange, size_t initialLength = aInto.Length(); size_t srcCursor = aRange.start(); - size_t remainingBytesToCopy = aRange.length(); + int remainingBytesToCopy = aRange.length(); while (remainingBytesToCopy > 0) { const size_t shm_idx = srcCursor / mChunkSize; const size_t ptrOffset = srcCursor % mChunkSize; - if (ptrOffset >= mChunkSize) { - break; - } const size_t copyRange = - std::min(remainingBytesToCopy, mChunkSize - ptrOffset); + std::min(remainingBytesToCopy, mChunkSize - ptrOffset); uint8_t* srcPtr = RefCountedShm::GetBytes(mSmallAllocs[shm_idx]) + ptrOffset; @@ -251,53 +248,6 @@ bool ShmSegmentsReader::Read(const layers::OffsetRange& aRange, return aInto.Length() - initialLength == aRange.length(); } -Maybe> ShmSegmentsReader::GetReadPointerLarge( - const layers::OffsetRange& aRange) { - // source = zero is for small allocs. - MOZ_RELEASE_ASSERT(aRange.source() != 0); - if (aRange.source() > mLargeAllocs.Length()) { - return Nothing(); - } - size_t id = aRange.source() - 1; - const ipc::Shmem& shm = mLargeAllocs[id]; - if (shm.Size() < aRange.length()) { - return Nothing(); - } - - uint8_t* srcPtr = shm.get(); - return Some(Range(srcPtr, aRange.length())); -} - -Maybe> ShmSegmentsReader::GetReadPointer( - const layers::OffsetRange& aRange) { - if (aRange.length() == 0) { - return Some(Range()); - } - - if (aRange.source() != 0) { - return GetReadPointerLarge(aRange); - } - - if (mChunkSize == 0 || - aRange.start() + aRange.length() > mChunkSize * mSmallAllocs.Length()) { - return Nothing(); - } - - size_t srcCursor = aRange.start(); - size_t remainingBytesToCopy = aRange.length(); - const size_t shm_idx = srcCursor / mChunkSize; - const size_t ptrOffset = srcCursor % mChunkSize; - // Return nothing if we can't return a pointer to the full range - if (ptrOffset >= mChunkSize || - mChunkSize - ptrOffset < remainingBytesToCopy) { - return Nothing(); - } - const size_t copyRange = - std::min(remainingBytesToCopy, mChunkSize - ptrOffset); - uint8_t* srcPtr = RefCountedShm::GetBytes(mSmallAllocs[shm_idx]) + ptrOffset; - return Some(Range(srcPtr, copyRange)); -} - IpcResourceUpdateQueue::IpcResourceUpdateQueue( layers::WebRenderBridgeChild* aAllocator, size_t aChunkSize) : mWriter(aAllocator, aChunkSize) {} diff --git a/gfx/layers/wr/IpcResourceUpdateQueue.h b/gfx/layers/wr/IpcResourceUpdateQueue.h index c3afd4eb40d8..0db163f8e500 100644 --- a/gfx/layers/wr/IpcResourceUpdateQueue.h +++ b/gfx/layers/wr/IpcResourceUpdateQueue.h @@ -71,34 +71,9 @@ class ShmSegmentsReader { bool Read(const layers::OffsetRange& aRange, wr::Vec& aInto); - // Get a read pointer, if possible, directly into the shm. If the range has - // been broken up into multiple chunks that can't be represented by a single - // range, nothing will be returned to indicate failure. - Maybe> GetReadPointer(const layers::OffsetRange& aRange); - - // Get a read pointer, if possible, directly into the shm. Otherwise, copy - // it into the Vec and return a pointer to that contiguous memory instead. - // If all fails, return nothing. - Maybe> GetReadPointerOrCopy(const layers::OffsetRange& aRange, - wr::Vec& aInto) { - if (Maybe> ptr = GetReadPointer(aRange)) { - return ptr; - } else { - size_t initialLength = aInto.Length(); - if (Read(aRange, aInto)) { - return Some(Range(aInto.Data() + initialLength, - aInto.Length() - initialLength)); - } else { - return Nothing(); - } - } - } - protected: bool ReadLarge(const layers::OffsetRange& aRange, wr::Vec& aInto); - Maybe> GetReadPointerLarge(const layers::OffsetRange& aRange); - const nsTArray& mSmallAllocs; const nsTArray& mLargeAllocs; size_t mChunkSize; @@ -112,8 +87,9 @@ class IpcResourceUpdateQueue { // we use here. The RefCountedShmem type used to allocate the chunks keeps a // 16 bytes header in the buffer which we account for here as well. So we pick // 64k - 2 * 4k - 16 = 57328 bytes as the default alloc size. - explicit IpcResourceUpdateQueue(layers::WebRenderBridgeChild* aAllocator, - size_t aChunkSize = 57328); + explicit IpcResourceUpdateQueue( + layers::WebRenderBridgeChild* aAllocator, + size_t aChunkSize = 57328); IpcResourceUpdateQueue(IpcResourceUpdateQueue&& aOther) noexcept; IpcResourceUpdateQueue& operator=(IpcResourceUpdateQueue&& aOther) noexcept; diff --git a/gfx/layers/wr/WebRenderBridgeParent.cpp b/gfx/layers/wr/WebRenderBridgeParent.cpp index ffd4cff4511f..81e8a59c442a 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.cpp +++ b/gfx/layers/wr/WebRenderBridgeParent.cpp @@ -8,7 +8,7 @@ #include "CompositableHost.h" #include "gfxEnv.h" -#include "gfxOTSUtils.h" +#include "gfxEnv.h" #include "GeckoProfiler.h" #include "GLContext.h" #include "GLContextProvider.h" @@ -430,48 +430,6 @@ void WebRenderBridgeParent::Destroy() { ClearResources(); } -struct WROTSAlloc { - wr::Vec mVec; - - void* Grow(void* aPtr, size_t aLength) { - if (aLength > mVec.Length()) { - mVec.Reserve(aLength - mVec.Length()); - } - return mVec.inner.data; - } - wr::Vec ShrinkToFit(void* aPtr, size_t aLength) { - wr::Vec result(std::move(mVec)); - result.inner.length = aLength; - return result; - } - void Free(void* aPtr) {} -}; - -static bool ReadRawFont(const OpAddRawFont& aOp, wr::ShmSegmentsReader& aReader, - wr::TransactionBuilder& aUpdates) { - wr::Vec sourceBytes; - Maybe> ptr = - aReader.GetReadPointerOrCopy(aOp.bytes(), sourceBytes); - if (ptr.isNothing()) { - return false; - } - Range& source = ptr.ref(); - // Attempt to sanitize the font before passing it along for updating - size_t lengthHint = gfxOTSContext::GuessSanitizedFontSize( - source.begin().get(), source.length()); - if (!lengthHint) { - return false; - } - gfxOTSExpandingMemoryStream output(lengthHint); - gfxOTSContext otsContext; - if (!otsContext.Process(&output, source.begin().get(), source.length())) { - return false; - } - wr::Vec bytes = output.forget(); - aUpdates.AddRawFont(aOp.key(), bytes, aOp.fontIndex()); - return true; -} - bool WebRenderBridgeParent::UpdateResources( const nsTArray& aResourceUpdates, const nsTArray& aSmallShmems, @@ -571,9 +529,12 @@ bool WebRenderBridgeParent::UpdateResources( break; } case OpUpdateResource::TOpAddRawFont: { - if (!ReadRawFont(cmd.get_OpAddRawFont(), reader, aUpdates)) { + const auto& op = cmd.get_OpAddRawFont(); + wr::Vec bytes; + if (!reader.Read(op.bytes(), bytes)) { return false; } + aUpdates.AddRawFont(op.key(), bytes, op.fontIndex()); break; } case OpUpdateResource::TOpAddFontDescriptor: { diff --git a/gfx/thebes/gfxOTSUtils.h b/gfx/thebes/gfxOTSUtils.h deleted file mode 100644 index a6587ded7c02..000000000000 --- a/gfx/thebes/gfxOTSUtils.h +++ /dev/null @@ -1,157 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * 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/. */ - -#ifndef GFX_OTS_UTILS_H -#define GFX_OTS_UTILS_H - -#include "gfxFontUtils.h" - -#include "opentype-sanitiser.h" - -struct gfxOTSMozAlloc { - void* Grow(void* aPtr, size_t aLength) { return moz_xrealloc(aPtr, aLength); } - void* ShrinkToFit(void* aPtr, size_t aLength) { - return moz_xrealloc(aPtr, aLength); - } - void Free(void* aPtr) { free(aPtr); } -}; - -// Based on ots::ExpandingMemoryStream from ots-memory-stream.h, -// adapted to use Mozilla allocators and to allow the final -// memory buffer to be adopted by the client. -template -class gfxOTSExpandingMemoryStream : public ots::OTSStream { - public: - // limit output/expansion to 256MB by default - enum { DEFAULT_LIMIT = 256 * 1024 * 1024 }; - - explicit gfxOTSExpandingMemoryStream(size_t initial, - size_t limit = DEFAULT_LIMIT) - : mLength(initial), mLimit(limit), mOff(0) { - mPtr = mAlloc.Grow(nullptr, mLength); - } - - ~gfxOTSExpandingMemoryStream() { mAlloc.Free(mPtr); } - - // Return the buffer, resized to fit its contents (as it may have been - // over-allocated during growth), and give up ownership of it so the - // caller becomes responsible to call free() when finished with it. - auto forget() { - auto p = mAlloc.ShrinkToFit(mPtr, mOff); - mPtr = nullptr; - return p; - } - - bool WriteRaw(const void* data, size_t length) override { - if ((mOff + length > mLength) || - (mLength > std::numeric_limits::max() - mOff)) { - if (mLength == mLimit) { - return false; - } - size_t newLength = (mLength + 1) * 2; - if (newLength < mLength) { - return false; - } - if (newLength > mLimit) { - newLength = mLimit; - } - mPtr = mAlloc.Grow(mPtr, newLength); - mLength = newLength; - return WriteRaw(data, length); - } - std::memcpy(static_cast(mPtr) + mOff, data, length); - mOff += length; - return true; - } - - bool Seek(off_t position) override { - if (position < 0) { - return false; - } - if (static_cast(position) > mLength) { - return false; - } - mOff = position; - return true; - } - - off_t Tell() const override { return mOff; } - - private: - AllocT mAlloc; - void* mPtr; - size_t mLength; - const size_t mLimit; - off_t mOff; -}; - -class MOZ_STACK_CLASS gfxOTSContext : public ots::OTSContext { - public: - gfxOTSContext() { - using namespace mozilla; - - // Whether to apply OTS validation to OpenType Layout tables - mCheckOTLTables = StaticPrefs::gfx_downloadable_fonts_otl_validation(); - // Whether to preserve Variation tables in downloaded fonts - mCheckVariationTables = - StaticPrefs::gfx_downloadable_fonts_validate_variation_tables(); - // Whether to preserve color bitmap glyphs - mKeepColorBitmaps = - StaticPrefs::gfx_downloadable_fonts_keep_color_bitmaps(); - } - - virtual ots::TableAction GetTableAction(uint32_t aTag) override { - // Preserve Graphite, color glyph and SVG tables, - // and possibly OTL and Variation tables (depending on prefs) - if ((!mCheckOTLTables && (aTag == TRUETYPE_TAG('G', 'D', 'E', 'F') || - aTag == TRUETYPE_TAG('G', 'P', 'O', 'S') || - aTag == TRUETYPE_TAG('G', 'S', 'U', 'B'))) || - (!mCheckVariationTables && - (aTag == TRUETYPE_TAG('a', 'v', 'a', 'r') || - aTag == TRUETYPE_TAG('c', 'v', 'a', 'r') || - aTag == TRUETYPE_TAG('f', 'v', 'a', 'r') || - aTag == TRUETYPE_TAG('g', 'v', 'a', 'r') || - aTag == TRUETYPE_TAG('H', 'V', 'A', 'R') || - aTag == TRUETYPE_TAG('M', 'V', 'A', 'R') || - aTag == TRUETYPE_TAG('S', 'T', 'A', 'T') || - aTag == TRUETYPE_TAG('V', 'V', 'A', 'R'))) || - aTag == TRUETYPE_TAG('S', 'V', 'G', ' ') || - aTag == TRUETYPE_TAG('C', 'O', 'L', 'R') || - aTag == TRUETYPE_TAG('C', 'P', 'A', 'L') || - (mKeepColorBitmaps && (aTag == TRUETYPE_TAG('C', 'B', 'D', 'T') || - aTag == TRUETYPE_TAG('C', 'B', 'L', 'C'))) || - false) { - return ots::TABLE_ACTION_PASSTHRU; - } - return ots::TABLE_ACTION_DEFAULT; - } - - static size_t GuessSanitizedFontSize(size_t aLength, - gfxUserFontType aFontType) { - switch (aFontType) { - case GFX_USERFONT_UNKNOWN: - return 0; - case GFX_USERFONT_WOFF: - return aLength * 2; - case GFX_USERFONT_WOFF2: - return aLength * 3; - default: - return aLength; - } - } - - static size_t GuessSanitizedFontSize(const uint8_t* aData, size_t aLength) { - gfxUserFontType fontType = - gfxFontUtils::DetermineFontDataType(aData, aLength); - return GuessSanitizedFontSize(aLength, fontType); - } - - private: - bool mCheckOTLTables; - bool mCheckVariationTables; - bool mKeepColorBitmaps; -}; - -#endif /* GFX_OTS_UTILS_H */ diff --git a/gfx/thebes/gfxUserFontSet.cpp b/gfx/thebes/gfxUserFontSet.cpp index 0a045952434a..ddb510135776 100644 --- a/gfx/thebes/gfxUserFontSet.cpp +++ b/gfx/thebes/gfxUserFontSet.cpp @@ -17,7 +17,9 @@ #include "gfxPlatformFontList.h" #include "mozilla/ServoStyleSet.h" #include "mozilla/PostTraversalTask.h" -#include "gfxOTSUtils.h" + +#include "opentype-sanitiser.h" +#include "ots-memory-stream.h" using namespace mozilla; @@ -33,6 +35,69 @@ mozilla::LogModule* gfxUserFontSet::GetUserFontsLog() { static uint64_t sFontSetGeneration = 0; +// Based on ots::ExpandingMemoryStream from ots-memory-stream.h, +// adapted to use Mozilla allocators and to allow the final +// memory buffer to be adopted by the client. +class ExpandingMemoryStream : public ots::OTSStream { + public: + ExpandingMemoryStream(size_t initial, size_t limit) + : mLength(initial), mLimit(limit), mOff(0) { + mPtr = moz_xmalloc(mLength); + } + + ~ExpandingMemoryStream() { free(mPtr); } + + // Return the buffer, resized to fit its contents (as it may have been + // over-allocated during growth), and give up ownership of it so the + // caller becomes responsible to call free() when finished with it. + void* forget() { + void* p = moz_xrealloc(mPtr, mOff); + mPtr = nullptr; + return p; + } + + bool WriteRaw(const void* data, size_t length) override { + if ((mOff + length > mLength) || + (mLength > std::numeric_limits::max() - mOff)) { + if (mLength == mLimit) { + return false; + } + size_t newLength = (mLength + 1) * 2; + if (newLength < mLength) { + return false; + } + if (newLength > mLimit) { + newLength = mLimit; + } + mPtr = moz_xrealloc(mPtr, newLength); + mLength = newLength; + return WriteRaw(data, length); + } + std::memcpy(static_cast(mPtr) + mOff, data, length); + mOff += length; + return true; + } + + bool Seek(off_t position) override { + if (position < 0) { + return false; + } + if (static_cast(position) > mLength) { + return false; + } + mOff = position; + return true; + } + + off_t Tell() const override { return mOff; } + + private: + void* mPtr; + size_t mLength; + const size_t mLimit; + off_t mOff; +}; + gfxUserFontEntry::gfxUserFontEntry( gfxUserFontSet* aFontSet, const nsTArray& aFontFaceSrcList, WeightRange aWeight, StretchRange aStretch, SlantStyleRange aStyle, @@ -115,12 +180,49 @@ gfxFont* gfxUserFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle) { return nullptr; } -class MOZ_STACK_CLASS gfxOTSMessageContext : public gfxOTSContext { +class MOZ_STACK_CLASS gfxOTSContext : public ots::OTSContext { public: - virtual ~gfxOTSMessageContext() { + gfxOTSContext() { + // Whether to apply OTS validation to OpenType Layout tables + mCheckOTLTables = StaticPrefs::gfx_downloadable_fonts_otl_validation(); + // Whether to preserve Variation tables in downloaded fonts + mCheckVariationTables = + StaticPrefs::gfx_downloadable_fonts_validate_variation_tables(); + // Whether to preserve color bitmap glyphs + mKeepColorBitmaps = + StaticPrefs::gfx_downloadable_fonts_keep_color_bitmaps(); + } + + virtual ~gfxOTSContext() { MOZ_ASSERT(mMessages.IsEmpty(), "should have called TakeMessages"); } + virtual ots::TableAction GetTableAction(uint32_t aTag) override { + // Preserve Graphite, color glyph and SVG tables, + // and possibly OTL and Variation tables (depending on prefs) + if ((!mCheckOTLTables && (aTag == TRUETYPE_TAG('G', 'D', 'E', 'F') || + aTag == TRUETYPE_TAG('G', 'P', 'O', 'S') || + aTag == TRUETYPE_TAG('G', 'S', 'U', 'B'))) || + (!mCheckVariationTables && + (aTag == TRUETYPE_TAG('a', 'v', 'a', 'r') || + aTag == TRUETYPE_TAG('c', 'v', 'a', 'r') || + aTag == TRUETYPE_TAG('f', 'v', 'a', 'r') || + aTag == TRUETYPE_TAG('g', 'v', 'a', 'r') || + aTag == TRUETYPE_TAG('H', 'V', 'A', 'R') || + aTag == TRUETYPE_TAG('M', 'V', 'A', 'R') || + aTag == TRUETYPE_TAG('S', 'T', 'A', 'T') || + aTag == TRUETYPE_TAG('V', 'V', 'A', 'R'))) || + aTag == TRUETYPE_TAG('S', 'V', 'G', ' ') || + aTag == TRUETYPE_TAG('C', 'O', 'L', 'R') || + aTag == TRUETYPE_TAG('C', 'P', 'A', 'L') || + (mKeepColorBitmaps && (aTag == TRUETYPE_TAG('C', 'B', 'D', 'T') || + aTag == TRUETYPE_TAG('C', 'B', 'L', 'C'))) || + false) { + return ots::TABLE_ACTION_PASSTHRU; + } + return ots::TABLE_ACTION_DEFAULT; + } + virtual void Message(int level, const char* format, ...) MSGFUNC_FMT_ATTR override { va_list va; @@ -157,6 +259,9 @@ class MOZ_STACK_CLASS gfxOTSMessageContext : public gfxOTSContext { private: nsTHashtable mWarningsIssued; nsTArray mMessages; + bool mCheckOTLTables; + bool mCheckVariationTables; + bool mKeepColorBitmaps; }; // Call the OTS library to sanitize an sfnt before attempting to use it. @@ -167,15 +272,22 @@ const uint8_t* gfxUserFontEntry::SanitizeOpenTypeData( aFontType = gfxFontUtils::DetermineFontDataType(aData, aLength); Telemetry::Accumulate(Telemetry::WEBFONT_FONTTYPE, uint32_t(aFontType)); - size_t lengthHint = gfxOTSContext::GuessSanitizedFontSize(aLength, aFontType); - if (!lengthHint) { + if (aFontType == GFX_USERFONT_UNKNOWN) { aSaneLength = 0; return nullptr; } - gfxOTSExpandingMemoryStream output(lengthHint); + uint32_t lengthHint = aLength; + if (aFontType == GFX_USERFONT_WOFF) { + lengthHint *= 2; + } else if (aFontType == GFX_USERFONT_WOFF2) { + lengthHint *= 3; + } - gfxOTSMessageContext otsContext; + // limit output/expansion to 256MB + ExpandingMemoryStream output(lengthHint, 1024 * 1024 * 256); + + gfxOTSContext otsContext; if (!otsContext.Process(&output, aData, aLength, aMessages)) { // Failed to decode/sanitize the font, so discard it. aSaneLength = 0; diff --git a/gfx/thebes/gfxUserFontSet.h b/gfx/thebes/gfxUserFontSet.h index 613559e1007b..97608d8b1be5 100644 --- a/gfx/thebes/gfxUserFontSet.h +++ b/gfx/thebes/gfxUserFontSet.h @@ -181,11 +181,11 @@ class gfxUserFontFamily : public gfxFontFamily { }; class gfxUserFontEntry; -class gfxOTSMessageContext; +class gfxOTSContext; class gfxUserFontSet { friend class gfxUserFontEntry; - friend class gfxOTSMessageContext; + friend class gfxOTSContext; public: typedef mozilla::FontStretch FontStretch; @@ -531,7 +531,7 @@ class gfxUserFontEntry : public gfxFontEntry { friend class gfxUserFontSet; friend class nsUserFontSet; friend class nsFontFaceLoader; - friend class gfxOTSMessageContext; + friend class gfxOTSContext; public: enum UserFontLoadState { diff --git a/gfx/thebes/moz.build b/gfx/thebes/moz.build index 8e5bcf1aea6f..36fb32164b1d 100644 --- a/gfx/thebes/moz.build +++ b/gfx/thebes/moz.build @@ -44,7 +44,6 @@ EXPORTS += [ 'gfxLineSegment.h', 'gfxMathTable.h', 'gfxMatrix.h', - 'gfxOTSUtils.h', 'gfxPattern.h', 'gfxPlatform.h', 'gfxPlatformFontList.h', diff --git a/gfx/webrender_bindings/WebRenderTypes.h b/gfx/webrender_bindings/WebRenderTypes.h index 79704eda6192..89510a344b2d 100644 --- a/gfx/webrender_bindings/WebRenderTypes.h +++ b/gfx/webrender_bindings/WebRenderTypes.h @@ -652,18 +652,12 @@ struct Vec final { inner.length = 0; } - uint8_t* Data() { return inner.data; } - size_t Length() { return inner.length; } - Range GetRange() { return Range(Data(), Length()); } - void PushBytes(Range aBytes) { wr_vec_u8_push_bytes(&inner, RangeToByteSlice(aBytes)); } - void Reserve(size_t aLength) { wr_vec_u8_reserve(&inner, aLength); } - ~Vec() { if (inner.data) { wr_vec_u8_free(inner); diff --git a/gfx/webrender_bindings/src/bindings.rs b/gfx/webrender_bindings/src/bindings.rs index f1f099e2f7dc..2cf83d269f9d 100644 --- a/gfx/webrender_bindings/src/bindings.rs +++ b/gfx/webrender_bindings/src/bindings.rs @@ -269,18 +269,11 @@ impl WrVecU8 { w } - fn reserve(&mut self, len: usize) { - let mut vec = self.flush_into_vec(); - vec.reserve(len); - *self = Self::from_vec(vec); - } - fn push_bytes(&mut self, bytes: &[u8]) { let mut vec = self.flush_into_vec(); vec.extend_from_slice(bytes); *self = Self::from_vec(vec); } - } #[no_mangle] @@ -288,11 +281,6 @@ pub extern "C" fn wr_vec_u8_push_bytes(v: &mut WrVecU8, bytes: ByteSlice) { v.push_bytes(bytes.as_slice()); } -#[no_mangle] -pub extern "C" fn wr_vec_u8_reserve(v: &mut WrVecU8, len: usize) { - v.reserve(len); -} - #[no_mangle] pub extern "C" fn wr_vec_u8_free(v: WrVecU8) { v.to_vec();