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