1e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com/*
2e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com * Copyright 2012 Google Inc.
3e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com *
4e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com * Use of this source code is governed by a BSD-style license that can be
5e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com * found in the LICENSE file.
6e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com */
7e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
8e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include "SkTypes.h"
9e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include "SkDWriteFontFileStream.h"
10e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include "SkHRESULT.h"
1111c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com#include "SkTemplates.h"
12f5cc5b140c1c00c536e02b5cfbe158bb2d5c2c15bungeman@google.com#include "SkTFitsIn.h"
136cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com#include "SkTScopedComPtr.h"
14e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
15e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com#include <dwrite.h>
16e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
17e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com///////////////////////////////////////////////////////////////////////////////
18e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com//  SkIDWriteFontFileStream
19e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
20e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comSkDWriteFontFileStream::SkDWriteFontFileStream(IDWriteFontFileStream* fontFileStream)
216cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    : fFontFileStream(SkRefComPtr(fontFileStream))
22e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    , fPos(0)
23e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    , fLockedMemory(NULL)
24e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    , fFragmentLock(NULL) {
25e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
26e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
27e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comSkDWriteFontFileStream::~SkDWriteFontFileStream() {
28e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    if (fFragmentLock) {
29e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        fFontFileStream->ReleaseFileFragment(fFragmentLock);
30e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    }
31e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
32e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
33e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comsize_t SkDWriteFontFileStream::read(void* buffer, size_t size) {
34e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    HRESULT hr = S_OK;
35e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
36e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    if (NULL == buffer) {
376cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        size_t fileSize = this->getLength();
386cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
396cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        if (fPos + size > fileSize) {
406cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com            size_t skipped = fileSize - fPos;
416cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com            fPos = fileSize;
426cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com            return skipped;
43e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        } else {
446cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com            fPos += size;
456cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com            return size;
46e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        }
47e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    }
48e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
49e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    const void* start;
50e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    void* fragmentLock;
51e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    hr = fFontFileStream->ReadFileFragment(&start, fPos, size, &fragmentLock);
52e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    if (SUCCEEDED(hr)) {
53e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        memcpy(buffer, start, size);
54e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        fFontFileStream->ReleaseFileFragment(fragmentLock);
55e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        fPos += size;
56e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        return size;
57e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    }
58e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
59e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    //The read may have failed because we asked for too much data.
606cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    size_t fileSize = this->getLength();
616cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    if (fPos + size <= fileSize) {
626cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        //This means we were within bounds, but failed for some other reason.
636cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        return 0;
646cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    }
656cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
666cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    size_t read = fileSize - fPos;
676cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    hr = fFontFileStream->ReadFileFragment(&start, fPos, read, &fragmentLock);
686cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    if (SUCCEEDED(hr)) {
696cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        memcpy(buffer, start, read);
706cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        fFontFileStream->ReleaseFileFragment(fragmentLock);
716cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        fPos = fileSize;
726cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        return read;
736cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    }
746cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
756cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    return 0;
766cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com}
776cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
786cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.combool SkDWriteFontFileStream::isAtEnd() const {
796cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    return fPos == this->getLength();
806cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com}
816cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
826cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.combool SkDWriteFontFileStream::rewind() {
836cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    fPos = 0;
846cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    return true;
856cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com}
866cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
876cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.comSkDWriteFontFileStream* SkDWriteFontFileStream::duplicate() const {
886cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    return SkNEW_ARGS(SkDWriteFontFileStream, (fFontFileStream.get()));
896cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com}
906cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
916cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.comsize_t SkDWriteFontFileStream::getPosition() const {
926cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    return fPos;
936cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com}
946cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
956cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.combool SkDWriteFontFileStream::seek(size_t position) {
966cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    size_t length = this->getLength();
976cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    fPos = (position > length) ? length : position;
986cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    return true;
996cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com}
1006cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
1016cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.combool SkDWriteFontFileStream::move(long offset) {
1026cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    return seek(fPos + offset);
1036cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com}
1046cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
1056cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.comSkDWriteFontFileStream* SkDWriteFontFileStream::fork() const {
1066cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    SkAutoTUnref<SkDWriteFontFileStream> that(this->duplicate());
1076cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    that->seek(fPos);
1086cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    return that.detach();
1096cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com}
1106cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
1116cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.comsize_t SkDWriteFontFileStream::getLength() const {
1126cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    HRESULT hr = S_OK;
113e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    UINT64 realFileSize = 0;
114e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    hr = fFontFileStream->GetFileSize(&realFileSize);
11511c9a55afd95078d14ab8cd7c1c5c0032af2a498bungeman@google.com    if (!SkTFitsIn<size_t>(realFileSize)) {
116e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        return 0;
117e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    }
1186cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    return static_cast<size_t>(realFileSize);
119e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
120e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
1216cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.comconst void* SkDWriteFontFileStream::getMemoryBase() {
1226cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    if (fLockedMemory) {
1236cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        return fLockedMemory;
1246cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    }
1256cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com
1266cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    UINT64 fileSize;
1276cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    HRNM(fFontFileStream->GetFileSize(&fileSize), "Could not get file size");
1286cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    HRNM(fFontFileStream->ReadFileFragment(&fLockedMemory, 0, fileSize, &fFragmentLock),
1296cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com         "Could not lock file fragment.");
1306cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    return fLockedMemory;
1316cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com}
132e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
133e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com///////////////////////////////////////////////////////////////////////////////
134e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com//  SkIDWriteFontFileStreamWrapper
135e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
136e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comHRESULT SkDWriteFontFileStreamWrapper::Create(SkStream* stream, SkDWriteFontFileStreamWrapper** streamFontFileStream) {
137e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    *streamFontFileStream = new SkDWriteFontFileStreamWrapper(stream);
138e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    if (NULL == streamFontFileStream) {
139e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        return E_OUTOFMEMORY;
140e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    }
141e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    return S_OK;
142e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
143e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
144e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comSkDWriteFontFileStreamWrapper::SkDWriteFontFileStreamWrapper(SkStream* stream)
1456cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    : fRefCount(1), fStream(SkRef(stream)) {
146e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
147e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
148e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comHRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::QueryInterface(REFIID iid, void** ppvObject) {
149e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) {
150e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        *ppvObject = this;
151e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        AddRef();
152e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        return S_OK;
153e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    } else {
154e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        *ppvObject = NULL;
155e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        return E_NOINTERFACE;
156e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    }
157e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
158e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
159e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comULONG STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::AddRef() {
160e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    return InterlockedIncrement(&fRefCount);
161e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
162e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
163e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comULONG STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::Release() {
164e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    ULONG newCount = InterlockedDecrement(&fRefCount);
165e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    if (0 == newCount) {
166e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        delete this;
167e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    }
168e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    return newCount;
169e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
170e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
171e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comHRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReadFileFragment(
172e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    void const** fragmentStart,
173e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    UINT64 fileOffset,
174e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    UINT64 fragmentSize,
175e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    void** fragmentContext)
176e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com{
177e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    // The loader is responsible for doing a bounds check.
178e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    UINT64 fileSize;
179e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    this->GetFileSize(&fileSize);
180e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    if (fileOffset > fileSize || fragmentSize > fileSize - fileOffset) {
181e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        *fragmentStart = NULL;
182e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        *fragmentContext = NULL;
183e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        return E_FAIL;
184e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    }
185e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
186f5cc5b140c1c00c536e02b5cfbe158bb2d5c2c15bungeman@google.com    if (!SkTFitsIn<size_t>(fileOffset + fragmentSize)) {
187e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        return E_FAIL;
188e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    }
189e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
190e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    const void* data = fStream->getMemoryBase();
19149f085dddff10473b6ebf832a974288300224e60bsalomon    if (data) {
192e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        *fragmentStart = static_cast<BYTE const*>(data) + static_cast<size_t>(fileOffset);
193e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        *fragmentContext = NULL;
194e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
195e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    } else {
196e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        //May be called from multiple threads.
197e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        SkAutoMutexAcquire ama(fStreamMutex);
198e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
199e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        *fragmentStart = NULL;
200e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        *fragmentContext = NULL;
201e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
202e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        if (!fStream->rewind()) {
203e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com            return E_FAIL;
204e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        }
205e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        if (fStream->skip(static_cast<size_t>(fileOffset)) != fileOffset) {
206e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com            return E_FAIL;
207e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        }
2086cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com        SkAutoTMalloc<uint8_t> streamData(static_cast<size_t>(fragmentSize));
209e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        if (fStream->read(streamData.get(), static_cast<size_t>(fragmentSize)) != fragmentSize) {
210e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com            return E_FAIL;
211e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        }
212e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
213e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        *fragmentStart = streamData.get();
214e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com        *fragmentContext = streamData.detach();
215e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    }
216e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    return S_OK;
217e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
218e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
219e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comvoid STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::ReleaseFileFragment(void* fragmentContext) {
2206cab1a4b6a68aa81237731308ff37a646d48f51cbungeman@google.com    sk_free(fragmentContext);
221e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
222e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
223e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comHRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::GetFileSize(UINT64* fileSize) {
224e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    *fileSize = fStream->getLength();
225e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    return S_OK;
226e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
227e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com
228e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.comHRESULT STDMETHODCALLTYPE SkDWriteFontFileStreamWrapper::GetLastWriteTime(UINT64* lastWriteTime) {
229e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    // The concept of last write time does not apply to this loader.
230e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    *lastWriteTime = 0;
231e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com    return E_NOTIMPL;
232e8f0592ae8b37e94d99f49816eb22e9fafde6d86bungeman@google.com}
233