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