gfx/2d/ScaledFontDWrite.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "ScaledFontDWrite.h"
     7 #include "PathD2D.h"
     8 #include "DrawTargetD2D.h"
     9 #include "Logging.h"
    11 #include <vector>
    13 namespace mozilla {
    14 namespace gfx {
    16 struct ffReferenceKey
    17 {
    18     uint8_t *mData;
    19     uint32_t mSize;
    20 };
    22 class DWriteFontFileLoader : public IDWriteFontFileLoader
    23 {
    24 public:
    25   DWriteFontFileLoader()
    26   {
    27   }
    29   // IUnknown interface
    30   IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject)
    31   {
    32     if (iid == __uuidof(IDWriteFontFileLoader)) {
    33       *ppObject = static_cast<IDWriteFontFileLoader*>(this);
    34       return S_OK;
    35     } else if (iid == __uuidof(IUnknown)) {
    36       *ppObject = static_cast<IUnknown*>(this);
    37       return S_OK;
    38     } else {
    39       return E_NOINTERFACE;
    40     }
    41   }
    43   IFACEMETHOD_(ULONG, AddRef)()
    44   {
    45     return 1;
    46   }
    48   IFACEMETHOD_(ULONG, Release)()
    49   {
    50     return 1;
    51   }
    53   // IDWriteFontFileLoader methods
    54   /**
    55     * Important! Note the key here -has- to be a pointer to an
    56     * ffReferenceKey object.
    57     */
    58   virtual HRESULT STDMETHODCALLTYPE 
    59     CreateStreamFromKey(void const* fontFileReferenceKey,
    60                         UINT32 fontFileReferenceKeySize,
    61                         OUT IDWriteFontFileStream** fontFileStream);
    63   /**
    64     * Gets the singleton loader instance. Note that when using this font
    65     * loader, the key must be a pointer to an FallibleTArray<uint8_t>. This
    66     * array will be empty when the function returns.
    67     */
    68   static IDWriteFontFileLoader* Instance()
    69   {
    70     if (!mInstance) {
    71       mInstance = new DWriteFontFileLoader();
    72       DrawTargetD2D::GetDWriteFactory()->
    73           RegisterFontFileLoader(mInstance);
    74     }
    75     return mInstance;
    76   }
    78 private:
    79   static IDWriteFontFileLoader* mInstance;
    80 }; 
    82 class DWriteFontFileStream : public IDWriteFontFileStream
    83 {
    84 public:
    85   /**
    86     * Used by the FontFileLoader to create a new font stream,
    87     * this font stream is created from data in memory. The memory
    88     * passed may be released after object creation, it will be
    89     * copied internally.
    90     *
    91     * @param aData Font data
    92     */
    93   DWriteFontFileStream(uint8_t *aData, uint32_t aSize);
    94   ~DWriteFontFileStream();
    96   // IUnknown interface
    97   IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject)
    98   {
    99     if (iid == __uuidof(IDWriteFontFileStream)) {
   100       *ppObject = static_cast<IDWriteFontFileStream*>(this);
   101       return S_OK;
   102     } else if (iid == __uuidof(IUnknown)) {
   103       *ppObject = static_cast<IUnknown*>(this);
   104       return S_OK;
   105     } else {
   106       return E_NOINTERFACE;
   107     }
   108   }
   110   IFACEMETHOD_(ULONG, AddRef)()
   111   {
   112     ++mRefCnt;
   113     return mRefCnt;
   114   }
   116   IFACEMETHOD_(ULONG, Release)()
   117   {
   118     --mRefCnt;
   119     if (mRefCnt == 0) {
   120       delete this;
   121       return 0;
   122     }
   123     return mRefCnt;
   124   }
   126   // IDWriteFontFileStream methods
   127   virtual HRESULT STDMETHODCALLTYPE ReadFileFragment(void const** fragmentStart,
   128                                                      UINT64 fileOffset,
   129                                                      UINT64 fragmentSize,
   130                                                      OUT void** fragmentContext);
   132   virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext);
   134   virtual HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize);
   136   virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime);
   138 private:
   139   std::vector<uint8_t> mData;
   140   uint32_t mRefCnt;
   141 };
   143 static BYTE
   144 GetSystemTextQuality()
   145 {
   146   BOOL font_smoothing;
   147   UINT smoothing_type;
   149   if (!SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0)) {
   150     return DEFAULT_QUALITY;
   151   }
   153   if (font_smoothing) {
   154       if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE,
   155                                 0, &smoothing_type, 0)) {
   156         return DEFAULT_QUALITY;
   157       }
   159       if (smoothing_type == FE_FONTSMOOTHINGCLEARTYPE) {
   160         return CLEARTYPE_QUALITY;
   161       }
   163       return ANTIALIASED_QUALITY;
   164   }
   166   return DEFAULT_QUALITY;
   167 }
   169 #define GASP_TAG 0x70736167
   170 #define GASP_DOGRAY 0x2
   172 static inline unsigned short
   173 readShort(const char *aBuf)
   174 {
   175   return (*aBuf << 8) | *(aBuf + 1);
   176 }
   178 static bool
   179 DoGrayscale(IDWriteFontFace *aDWFace, Float ppem)
   180 {
   181   void *tableContext;
   182   char *tableData;
   183   UINT32 tableSize;
   184   BOOL exists;
   185   aDWFace->TryGetFontTable(GASP_TAG, (const void**)&tableData, &tableSize, &tableContext, &exists);
   187   if (exists) {
   188     if (tableSize < 4) {
   189       aDWFace->ReleaseFontTable(tableContext);
   190       return true;
   191     }
   192     struct gaspRange {
   193       unsigned short maxPPEM; // Stored big-endian
   194       unsigned short behavior; // Stored big-endian
   195     };
   196     unsigned short numRanges = readShort(tableData + 2);
   197     if (tableSize < (UINT)4 + numRanges * 4) {
   198       aDWFace->ReleaseFontTable(tableContext);
   199       return true;
   200     }
   201     gaspRange *ranges = (gaspRange *)(tableData + 4);
   202     for (int i = 0; i < numRanges; i++) {
   203       if (readShort((char*)&ranges[i].maxPPEM) > ppem) {
   204         if (!(readShort((char*)&ranges[i].behavior) & GASP_DOGRAY)) {
   205           aDWFace->ReleaseFontTable(tableContext);
   206           return false;
   207         }
   208         break;
   209       }
   210     }
   211     aDWFace->ReleaseFontTable(tableContext);
   212   }
   213   return true;
   214 }
   216 IDWriteFontFileLoader* DWriteFontFileLoader::mInstance = nullptr;
   218 HRESULT STDMETHODCALLTYPE
   219 DWriteFontFileLoader::CreateStreamFromKey(const void *fontFileReferenceKey, 
   220                                           UINT32 fontFileReferenceKeySize, 
   221                                           IDWriteFontFileStream **fontFileStream)
   222 {
   223   if (!fontFileReferenceKey || !fontFileStream) {
   224     return E_POINTER;
   225   }
   227   const ffReferenceKey *key = static_cast<const ffReferenceKey*>(fontFileReferenceKey);
   228   *fontFileStream = 
   229     new DWriteFontFileStream(key->mData, key->mSize);
   231   if (!*fontFileStream) {
   232     return E_OUTOFMEMORY;
   233   }
   234   (*fontFileStream)->AddRef();
   235   return S_OK;
   236 }
   238 DWriteFontFileStream::DWriteFontFileStream(uint8_t *aData, uint32_t aSize)
   239   : mRefCnt(0)
   240 {
   241   mData.resize(aSize);
   242   memcpy(&mData.front(), aData, aSize);
   243 }
   245 DWriteFontFileStream::~DWriteFontFileStream()
   246 {
   247 }
   249 HRESULT STDMETHODCALLTYPE
   250 DWriteFontFileStream::GetFileSize(UINT64 *fileSize)
   251 {
   252   *fileSize = mData.size();
   253   return S_OK;
   254 }
   256 HRESULT STDMETHODCALLTYPE
   257 DWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime)
   258 {
   259   return E_NOTIMPL;
   260 }
   262 HRESULT STDMETHODCALLTYPE
   263 DWriteFontFileStream::ReadFileFragment(const void **fragmentStart,
   264                                        UINT64 fileOffset,
   265                                        UINT64 fragmentSize,
   266                                        void **fragmentContext)
   267 {
   268   // We are required to do bounds checking.
   269   if (fileOffset + fragmentSize > mData.size()) {
   270     return E_FAIL;
   271   }
   273   // truncate the 64 bit fileOffset to size_t sized index into mData
   274   size_t index = static_cast<size_t>(fileOffset);
   276   // We should be alive for the duration of this.
   277   *fragmentStart = &mData[index];
   278   *fragmentContext = nullptr;
   279   return S_OK;
   280 }
   282 void STDMETHODCALLTYPE
   283 DWriteFontFileStream::ReleaseFileFragment(void *fragmentContext)
   284 {
   285 }
   287 ScaledFontDWrite::ScaledFontDWrite(uint8_t *aData, uint32_t aSize,
   288                                    uint32_t aIndex, Float aGlyphSize)
   289   : ScaledFontBase(aGlyphSize)
   290 {
   291   IDWriteFactory *factory = DrawTargetD2D::GetDWriteFactory();
   293   ffReferenceKey key;
   294   key.mData = aData;
   295   key.mSize = aSize;
   297   RefPtr<IDWriteFontFile> fontFile;
   298   if (FAILED(factory->CreateCustomFontFileReference(&key, sizeof(ffReferenceKey), DWriteFontFileLoader::Instance(), byRef(fontFile)))) {
   299     gfxWarning() << "Failed to load font file from data!";
   300     return;
   301   }
   303   IDWriteFontFile *ff = fontFile;
   304   if (FAILED(factory->CreateFontFace(DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &ff, aIndex, DWRITE_FONT_SIMULATIONS_NONE, byRef(mFontFace)))) {
   305     gfxWarning() << "Failed to create font face from font file data!";
   306   }
   307 }
   309 TemporaryRef<Path>
   310 ScaledFontDWrite::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget)
   311 {
   312   if (aTarget->GetType() != BackendType::DIRECT2D) {
   313     return ScaledFontBase::GetPathForGlyphs(aBuffer, aTarget);
   314   }
   316   RefPtr<PathBuilder> pathBuilder = aTarget->CreatePathBuilder();
   318   PathBuilderD2D *pathBuilderD2D =
   319     static_cast<PathBuilderD2D*>(pathBuilder.get());
   321   CopyGlyphsToSink(aBuffer, pathBuilderD2D->GetSink());
   323   return pathBuilder->Finish();
   324 }
   326 void
   327 ScaledFontDWrite::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, BackendType aBackendType, const Matrix *aTransformHint)
   328 {
   329   if (aBackendType != BackendType::DIRECT2D) {
   330     ScaledFontBase::CopyGlyphsToBuilder(aBuffer, aBuilder, aBackendType, aTransformHint);
   331     return;
   332   }
   334   PathBuilderD2D *pathBuilderD2D =
   335     static_cast<PathBuilderD2D*>(aBuilder);
   337   CopyGlyphsToSink(aBuffer, pathBuilderD2D->GetSink());
   338 }
   340 void
   341 ScaledFontDWrite::CopyGlyphsToSink(const GlyphBuffer &aBuffer, ID2D1GeometrySink *aSink)
   342 {
   343   std::vector<UINT16> indices;
   344   std::vector<FLOAT> advances;
   345   std::vector<DWRITE_GLYPH_OFFSET> offsets;
   346   indices.resize(aBuffer.mNumGlyphs);
   347   advances.resize(aBuffer.mNumGlyphs);
   348   offsets.resize(aBuffer.mNumGlyphs);
   350   memset(&advances.front(), 0, sizeof(FLOAT) * aBuffer.mNumGlyphs);
   351   for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) {
   352     indices[i] = aBuffer.mGlyphs[i].mIndex;
   353     offsets[i].advanceOffset = aBuffer.mGlyphs[i].mPosition.x;
   354     offsets[i].ascenderOffset = -aBuffer.mGlyphs[i].mPosition.y;
   355   }
   357   mFontFace->GetGlyphRunOutline(mSize, &indices.front(), &advances.front(),
   358                                 &offsets.front(), aBuffer.mNumGlyphs,
   359                                 FALSE, FALSE, aSink);
   360 }
   362 bool
   363 ScaledFontDWrite::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton)
   364 {
   365   UINT32 fileCount = 0;
   366   mFontFace->GetFiles(&fileCount, nullptr);
   368   if (fileCount > 1) {
   369     MOZ_ASSERT(false);
   370     return false;
   371   }
   373   RefPtr<IDWriteFontFile> file;
   374   mFontFace->GetFiles(&fileCount, byRef(file));
   376   const void *referenceKey;
   377   UINT32 refKeySize;
   378   // XXX - This can currently crash for webfonts, as when we get the reference
   379   // key out of the file, that can be an invalid reference key for the loader
   380   // we use it with. The fix to this is not obvious but it will probably 
   381   // have to happen inside thebes.
   382   file->GetReferenceKey(&referenceKey, &refKeySize);
   384   RefPtr<IDWriteFontFileLoader> loader;
   385   file->GetLoader(byRef(loader));
   387   RefPtr<IDWriteFontFileStream> stream;
   388   loader->CreateStreamFromKey(referenceKey, refKeySize, byRef(stream));
   390   UINT64 fileSize64;
   391   stream->GetFileSize(&fileSize64);
   392   if (fileSize64 > UINT32_MAX) {
   393     MOZ_ASSERT(false);
   394     return false;
   395   }
   397   uint32_t fileSize = static_cast<uint32_t>(fileSize64);
   398   const void *fragmentStart;
   399   void *context;
   400   stream->ReadFileFragment(&fragmentStart, 0, fileSize, &context);
   402   aDataCallback((uint8_t*)fragmentStart, fileSize, mFontFace->GetIndex(), mSize, aBaton);
   404   stream->ReleaseFileFragment(context);
   406   return true;
   407 }
   409 AntialiasMode
   410 ScaledFontDWrite::GetDefaultAAMode()
   411 {
   412   AntialiasMode defaultMode = AntialiasMode::SUBPIXEL;
   414   switch (GetSystemTextQuality()) {
   415   case CLEARTYPE_QUALITY:
   416     defaultMode = AntialiasMode::SUBPIXEL;
   417     break;
   418   case ANTIALIASED_QUALITY:
   419     defaultMode = AntialiasMode::GRAY;
   420     break;
   421   case DEFAULT_QUALITY:
   422     defaultMode = AntialiasMode::NONE;
   423     break;
   424   }
   426   if (defaultMode == AntialiasMode::GRAY) {
   427     if (!DoGrayscale(mFontFace, mSize)) {
   428       defaultMode = AntialiasMode::NONE;
   429     }
   430   }
   431   return defaultMode;
   432 }
   434 }
   435 }

mercurial