Bug 906521. Part 6: Make gfxSVGGlyphs understand the new table format. r=jfkthame
authorRobert O'Callahan <robert@ocallahan.org>
Tue, 20 Aug 2013 01:08:43 +1200
changeset 144299 641b974b1a8f3c750e7461d7a24dc46ae46d643d
parent 144298 862f41ab28b2f0cc8da46bad57aae83d92362748
child 144300 a9932e507b43e712b3e5d79256040303ff63904b
push id25157
push userryanvm@gmail.com
push dateMon, 26 Aug 2013 13:17:12 +0000
treeherdermozilla-central@14b1e8c2957e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjfkthame
bugs906521
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 906521. Part 6: Make gfxSVGGlyphs understand the new table format. r=jfkthame This also adds a bunch of buffer sanity checks to the code. This may not be strictly necessary, thanks to OTS, but I think we should code defensively here too.
gfx/thebes/gfxSVGGlyphs.cpp
gfx/thebes/gfxSVGGlyphs.h
--- a/gfx/thebes/gfxSVGGlyphs.cpp
+++ b/gfx/thebes/gfxSVGGlyphs.cpp
@@ -41,19 +41,31 @@ mozilla::gfx::UserDataKey gfxTextObjectP
 const float gfxSVGGlyphs::SVG_UNITS_PER_EM = 1000.0f;
 
 const gfxRGBA SimpleTextObjectPaint::sZero = gfxRGBA(0.0f, 0.0f, 0.0f, 0.0f);
 
 gfxSVGGlyphs::gfxSVGGlyphs(hb_blob_t *aSVGTable)
 {
     mSVGData = aSVGTable;
 
-    const char* svgData = hb_blob_get_data(mSVGData, nullptr);
+    unsigned int length;
+    const char* svgData = hb_blob_get_data(mSVGData, &length);
     mHeader = reinterpret_cast<const Header*>(svgData);
-    mIndex = reinterpret_cast<const IndexEntry*>(svgData + sizeof(Header));
+    mDocIndex = nullptr;
+
+    if (sizeof(Header) <= length && uint16_t(mHeader->mVersion) == 0 &&
+        uint64_t(mHeader->mDocIndexOffset) + 2 <= length) {
+        const DocIndex* docIndex = reinterpret_cast<const DocIndex*>
+            (svgData + mHeader->mDocIndexOffset);
+        // Limit the number of documents to avoid overflow
+        if (uint64_t(mHeader->mDocIndexOffset) + 2 +
+                uint16_t(docIndex->mNumEntries) * sizeof(IndexEntry) <= length) {
+            mDocIndex = docIndex;
+        }
+    }
 
     mGlyphDocs.Init();
     mGlyphIdMap.Init();
 }
 
 gfxSVGGlyphs::~gfxSVGGlyphs()
 {
     hb_blob_destroy(mSVGData);
@@ -83,36 +95,40 @@ gfxSVGGlyphs::CompareIndexEntries(const 
         return 1;
     }
     return 0;
 }
 
 gfxSVGGlyphsDocument *
 gfxSVGGlyphs::FindOrCreateGlyphsDocument(uint32_t aGlyphId)
 {
-    if (uint16_t(mHeader->mVersion) != 0) {
-        // Version not understood
+    if (!mDocIndex) {
+        // Invalid table
         return nullptr;
     }
 
-    IndexEntry *entry = (IndexEntry*)bsearch(&aGlyphId, mIndex,
-                                             uint16_t(mHeader->mIndexLength),
+    IndexEntry *entry = (IndexEntry*)bsearch(&aGlyphId, mDocIndex->mEntries,
+                                             uint16_t(mDocIndex->mNumEntries),
                                              sizeof(IndexEntry),
                                              CompareIndexEntries);
     if (!entry) {
         return nullptr;
     }
 
     gfxSVGGlyphsDocument *result = mGlyphDocs.Get(entry->mDocOffset);
 
     if (!result) {
-        const uint8_t *data = (const uint8_t*)hb_blob_get_data(mSVGData, nullptr);
-        result = new gfxSVGGlyphsDocument(data + entry->mDocOffset,
-                                          entry->mDocLength);
-        mGlyphDocs.Put(entry->mDocOffset, result);
+        unsigned int length;
+        const uint8_t *data = (const uint8_t*)hb_blob_get_data(mSVGData, &length);
+        if (entry->mDocOffset > 0 &&
+            uint64_t(mHeader->mDocIndexOffset) + entry->mDocOffset + entry->mDocLength <= length) {
+            result = new gfxSVGGlyphsDocument(data + mHeader->mDocIndexOffset + entry->mDocOffset,
+                                              entry->mDocLength);
+            mGlyphDocs.Put(entry->mDocOffset, result);
+        }
     }
 
     return result;
 }
 
 nsresult
 gfxSVGGlyphsDocument::SetupPresentation()
 {
--- a/gfx/thebes/gfxSVGGlyphs.h
+++ b/gfx/thebes/gfxSVGGlyphs.h
@@ -122,25 +122,31 @@ private:
 
     nsClassHashtable<nsUint32HashKey, gfxSVGGlyphsDocument> mGlyphDocs;
     nsBaseHashtable<nsUint32HashKey, Element*, Element*> mGlyphIdMap;
 
     hb_blob_t *mSVGData;
 
     const struct Header {
         mozilla::AutoSwap_PRUint16 mVersion;
-        mozilla::AutoSwap_PRUint16 mIndexLength;
+        mozilla::AutoSwap_PRUint32 mDocIndexOffset;
+        mozilla::AutoSwap_PRUint32 mColorPalettesOffset;
     } *mHeader;
 
-    const struct IndexEntry {
+    struct IndexEntry {
         mozilla::AutoSwap_PRUint16 mStartGlyph;
         mozilla::AutoSwap_PRUint16 mEndGlyph;
         mozilla::AutoSwap_PRUint32 mDocOffset;
         mozilla::AutoSwap_PRUint32 mDocLength;
-    } *mIndex;
+    };
+
+    const struct DocIndex {
+      mozilla::AutoSwap_PRUint16 mNumEntries;
+      IndexEntry mEntries[1]; /* actual length = mNumEntries */
+    } *mDocIndex;
 
     static int CompareIndexEntries(const void *_a, const void *_b);
 };
 
 /**
  * Used for trickling down paint information through to SVG glyphs.
  * Will be extended in later patch.
  */