Home | History | Annotate | Download | only in win
      1 /*
      2  * Copyright 2012 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkTypes.h"
      9 #include "SkDWriteFontFileStream.h"
     10 #include "SkHRESULT.h"
     11 #include "SkTemplates.h"
     12 #include "SkTFitsIn.h"
     13 #include "SkTScopedComPtr.h"
     14 
     15 #include <dwrite.h>
     16 
     17 ///////////////////////////////////////////////////////////////////////////////
     18 //  SkIDWriteFontFileStream
     19 
     20 SkDWriteFontFileStream::SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream)
     21     : fFontFileStream(SkRefComPtr(fontFileStream))
     22     , fPos(0)
     23     , fLockedMemory(NULL)
     24     , fFragmentLock(NULL) {
     25 }
     26 
     27 SkDWriteFontFileStream::~SkDWriteFontFileStream() {
     28     if (fFragmentLock) {
     29         fFontFileStream->ReleaseFileFragment(fFragmentLock);
     30     }
     31 }
     32 
     33 size_t SkDWriteFontFileStream::read(void* buffer, size_t size) {
     34     HRESULT hr = S_OK;
     35 
     36     if (NULL == buffer) {
     37         size_t fileSize = this->getLength();
     38 
     39         if (fPos + size > fileSize) {
     40             size_t skipped = fileSize - fPos;
     41             fPos = fileSize;
     42             return skipped;
     43         } else {
     44             fPos += size;
     45             return size;
     46         }
     47     }
     48 
     49     const void* start;
     50     void* fragmentLock;
     51     hr = fFontFileStream->ReadFileFragment(&start, fPos, size, &fragmentLock);
     52     if (SUCCEEDED(hr)) {
     53         memcpy(buffer, start, size);
     54         fFontFileStream->ReleaseFileFragment(fragmentLock);
     55         fPos += size;
     56         return size;
     57     }
     58 
     59     //The read may have failed because we asked for too much data.
     60     size_t fileSize = this->getLength();
     61     if (fPos + size <= fileSize) {
     62         //This means we were within bounds, but failed for some other reason.
     63         return 0;
     64     }
     65 
     66     size_t read = fileSize - fPos;
     67     hr = fFontFileStream->ReadFileFragment(&start, fPos, read, &fragmentLock);
     68     if (SUCCEEDED(hr)) {
     69         memcpy(buffer, start, read);
     70         fFontFileStream->ReleaseFileFragment(fragmentLock);
     71         fPos = fileSize;
     72         return read;
     73     }
     74 
     75     return 0;
     76 }
     77 
     78 bool SkDWriteFontFileStream::isAtEnd() const {
     79     return fPos == this->getLength();
     80 }
     81 
     82 bool SkDWriteFontFileStream::rewind() {
     83     fPos = 0;
     84     return true;
     85 }
     86 
     87 SkDWriteFontFileStream* SkDWriteFontFileStream::duplicate() const {
     88     return SkNEW_ARGS(SkDWriteFontFileStream, (fFontFileStream.get()));
     89 }
     90 
     91 size_t SkDWriteFontFileStream::getPosition() const {
     92     return fPos;
     93 }
     94 
     95 bool SkDWriteFontFileStream::seek(size_t position) {
     96     size_t length = this->getLength();
     97     fPos = (position > length) ? length : position;
     98     return true;
     99 }
    100 
    101 bool SkDWriteFontFileStream::move(long offset) {
    102     return seek(fPos + offset);
    103 }
    104 
    105 SkDWriteFontFileStream* SkDWriteFontFileStream::fork() const {
    106     SkAutoTUnref<SkDWriteFontFileStream> that(this->duplicate());
    107     that->seek(fPos);
    108     return that.detach();
    109 }
    110 
    111 size_t SkDWriteFontFileStream::getLength() const {
    112     HRESULT hr = S_OK;
    113     UINT64 realFileSize = 0;
    114     hr = fFontFileStream->GetFileSize(&realFileSize);
    115     if (!SkTFitsIn<size_t>(realFileSize)) {
    116         return 0;
    117     }
    118     return static_cast<size_t>(realFileSize);
    119 }
    120 
    121 const void* SkDWriteFontFileStream::getMemoryBase() {
    122     if (fLockedMemory) {
    123         return fLockedMemory;
    124     }
    125 
    126     UINT64 fileSize;
    127     HRNM(fFontFileStream->GetFileSize(&fileSize), "Could not get file size");
    128     HRNM(fFontFileStream->ReadFileFragment(&fLockedMemory, 0, fileSize, &fFragmentLock),
    129          "Could not lock file fragment.");
    130     return fLockedMemory;
    131 }
    132 
    133 ///////////////////////////////////////////////////////////////////////////////
    134 //  SkIDWriteFontFileStreamWrapper
    135 
    136 HRESULT SkDWriteFontFileStreamWrapper::Create(SkStream* stream, SkDWriteFontFileStreamWrapper** streamFontFileStream) {
    137     *streamFontFileStream = new SkDWriteFontFileStreamWrapper(stream);
    138     if (NULL == streamFontFileStream) {
    139         return E_OUTOFMEMORY;
    140     }
    141     return S_OK;
    142 }
    143 
    144 SkDWriteFontFileStreamWrapper::SkDWriteFontFileStreamWrapper(SkStream* stream)
    145     : fRefCount(1), fStream(SkRef(stream)) {
    146 }
    147 
    148 HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::QueryInterface(REFIID iid, void** ppvObject) {
    149     if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) {
    150         *ppvObject = this;
    151         AddRef();
    152         return S_OK;
    153     } else {
    154         *ppvObject = NULL;
    155         return E_NOINTERFACE;
    156     }
    157 }
    158 
    159 ULONG STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::AddRef() {
    160     return InterlockedIncrement(&fRefCount);
    161 }
    162 
    163 ULONG STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::Release() {
    164     ULONG newCount = InterlockedDecrement(&fRefCount);
    165     if (0 == newCount) {
    166         delete this;
    167     }
    168     return newCount;
    169 }
    170 
    171 HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReadFileFragment(
    172     void const** fragmentStart,
    173     UINT64 fileOffset,
    174     UINT64 fragmentSize,
    175     void** fragmentContext)
    176 {
    177     // The loader is responsible for doing a bounds check.
    178     UINT64 fileSize;
    179     this->GetFileSize(&fileSize);
    180     if (fileOffset > fileSize || fragmentSize > fileSize - fileOffset) {
    181         *fragmentStart = NULL;
    182         *fragmentContext = NULL;
    183         return E_FAIL;
    184     }
    185 
    186     if (!SkTFitsIn<size_t>(fileOffset + fragmentSize)) {
    187         return E_FAIL;
    188     }
    189 
    190     const void* data = fStream->getMemoryBase();
    191     if (NULL != data) {
    192         *fragmentStart = static_cast<BYTE const*>(data) + static_cast<size_t>(fileOffset);
    193         *fragmentContext = NULL;
    194 
    195     } else {
    196         //May be called from multiple threads.
    197         SkAutoMutexAcquire ama(fStreamMutex);
    198 
    199         *fragmentStart = NULL;
    200         *fragmentContext = NULL;
    201 
    202         if (!fStream->rewind()) {
    203             return E_FAIL;
    204         }
    205         if (fStream->skip(static_cast<size_t>(fileOffset)) != fileOffset) {
    206             return E_FAIL;
    207         }
    208         SkAutoTMalloc<uint8_t> streamData(static_cast<size_t>(fragmentSize));
    209         if (fStream->read(streamData.get(), static_cast<size_t>(fragmentSize)) != fragmentSize) {
    210             return E_FAIL;
    211         }
    212 
    213         *fragmentStart = streamData.get();
    214         *fragmentContext = streamData.detach();
    215     }
    216     return S_OK;
    217 }
    218 
    219 void STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReleaseFileFragment(void* fragmentContext) {
    220     sk_free(fragmentContext);
    221 }
    222 
    223 HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::GetFileSize(UINT64* fileSize) {
    224     *fileSize = fStream->getLength();
    225     return S_OK;
    226 }
    227 
    228 HRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::GetLastWriteTime(UINT64* lastWriteTime) {
    229     // The concept of last write time does not apply to this loader.
    230     *lastWriteTime = 0;
    231     return E_NOTIMPL;
    232 }
    233