1*2d1272b8SAndroid Build Coastguard Worker /*
2*2d1272b8SAndroid Build Coastguard Worker * Copyright © 2015-2019 Ebrahim Byagowi
3*2d1272b8SAndroid Build Coastguard Worker *
4*2d1272b8SAndroid Build Coastguard Worker * This is part of HarfBuzz, a text shaping library.
5*2d1272b8SAndroid Build Coastguard Worker *
6*2d1272b8SAndroid Build Coastguard Worker * Permission is hereby granted, without written agreement and without
7*2d1272b8SAndroid Build Coastguard Worker * license or royalty fees, to use, copy, modify, and distribute this
8*2d1272b8SAndroid Build Coastguard Worker * software and its documentation for any purpose, provided that the
9*2d1272b8SAndroid Build Coastguard Worker * above copyright notice and the following two paragraphs appear in
10*2d1272b8SAndroid Build Coastguard Worker * all copies of this software.
11*2d1272b8SAndroid Build Coastguard Worker *
12*2d1272b8SAndroid Build Coastguard Worker * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13*2d1272b8SAndroid Build Coastguard Worker * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14*2d1272b8SAndroid Build Coastguard Worker * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15*2d1272b8SAndroid Build Coastguard Worker * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16*2d1272b8SAndroid Build Coastguard Worker * DAMAGE.
17*2d1272b8SAndroid Build Coastguard Worker *
18*2d1272b8SAndroid Build Coastguard Worker * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19*2d1272b8SAndroid Build Coastguard Worker * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20*2d1272b8SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21*2d1272b8SAndroid Build Coastguard Worker * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22*2d1272b8SAndroid Build Coastguard Worker * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23*2d1272b8SAndroid Build Coastguard Worker */
24*2d1272b8SAndroid Build Coastguard Worker
25*2d1272b8SAndroid Build Coastguard Worker #include "hb.hh"
26*2d1272b8SAndroid Build Coastguard Worker
27*2d1272b8SAndroid Build Coastguard Worker #ifdef HAVE_DIRECTWRITE
28*2d1272b8SAndroid Build Coastguard Worker
29*2d1272b8SAndroid Build Coastguard Worker #include "hb-shaper-impl.hh"
30*2d1272b8SAndroid Build Coastguard Worker
31*2d1272b8SAndroid Build Coastguard Worker #include <dwrite_1.h>
32*2d1272b8SAndroid Build Coastguard Worker
33*2d1272b8SAndroid Build Coastguard Worker #include "hb-directwrite.h"
34*2d1272b8SAndroid Build Coastguard Worker
35*2d1272b8SAndroid Build Coastguard Worker #include "hb-ms-feature-ranges.hh"
36*2d1272b8SAndroid Build Coastguard Worker
37*2d1272b8SAndroid Build Coastguard Worker /**
38*2d1272b8SAndroid Build Coastguard Worker * SECTION:hb-directwrite
39*2d1272b8SAndroid Build Coastguard Worker * @title: hb-directwrite
40*2d1272b8SAndroid Build Coastguard Worker * @short_description: DirectWrite integration
41*2d1272b8SAndroid Build Coastguard Worker * @include: hb-directwrite.h
42*2d1272b8SAndroid Build Coastguard Worker *
43*2d1272b8SAndroid Build Coastguard Worker * Functions for using HarfBuzz with DirectWrite fonts.
44*2d1272b8SAndroid Build Coastguard Worker **/
45*2d1272b8SAndroid Build Coastguard Worker
46*2d1272b8SAndroid Build Coastguard Worker /* Declare object creator for dynamic support of DWRITE */
47*2d1272b8SAndroid Build Coastguard Worker typedef HRESULT (WINAPI *t_DWriteCreateFactory)(
48*2d1272b8SAndroid Build Coastguard Worker DWRITE_FACTORY_TYPE factoryType,
49*2d1272b8SAndroid Build Coastguard Worker REFIID iid,
50*2d1272b8SAndroid Build Coastguard Worker IUnknown **factory
51*2d1272b8SAndroid Build Coastguard Worker );
52*2d1272b8SAndroid Build Coastguard Worker
53*2d1272b8SAndroid Build Coastguard Worker
54*2d1272b8SAndroid Build Coastguard Worker /*
55*2d1272b8SAndroid Build Coastguard Worker * DirectWrite font stream helpers
56*2d1272b8SAndroid Build Coastguard Worker */
57*2d1272b8SAndroid Build Coastguard Worker
58*2d1272b8SAndroid Build Coastguard Worker // This is a font loader which provides only one font (unlike its original design).
59*2d1272b8SAndroid Build Coastguard Worker // For a better implementation which was also source of this
60*2d1272b8SAndroid Build Coastguard Worker // and DWriteFontFileStream, have a look at to NativeFontResourceDWrite.cpp in Mozilla
61*2d1272b8SAndroid Build Coastguard Worker class DWriteFontFileLoader : public IDWriteFontFileLoader
62*2d1272b8SAndroid Build Coastguard Worker {
63*2d1272b8SAndroid Build Coastguard Worker private:
64*2d1272b8SAndroid Build Coastguard Worker IDWriteFontFileStream *mFontFileStream;
65*2d1272b8SAndroid Build Coastguard Worker public:
DWriteFontFileLoader(IDWriteFontFileStream * fontFileStream)66*2d1272b8SAndroid Build Coastguard Worker DWriteFontFileLoader (IDWriteFontFileStream *fontFileStream)
67*2d1272b8SAndroid Build Coastguard Worker { mFontFileStream = fontFileStream; }
68*2d1272b8SAndroid Build Coastguard Worker
69*2d1272b8SAndroid Build Coastguard Worker // IUnknown interface
IFACEMETHOD(QueryInterface)70*2d1272b8SAndroid Build Coastguard Worker IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
71*2d1272b8SAndroid Build Coastguard Worker { return S_OK; }
IFACEMETHOD_(ULONG,AddRef)72*2d1272b8SAndroid Build Coastguard Worker IFACEMETHOD_ (ULONG, AddRef) () { return 1; }
IFACEMETHOD_(ULONG,Release)73*2d1272b8SAndroid Build Coastguard Worker IFACEMETHOD_ (ULONG, Release) () { return 1; }
74*2d1272b8SAndroid Build Coastguard Worker
75*2d1272b8SAndroid Build Coastguard Worker // IDWriteFontFileLoader methods
76*2d1272b8SAndroid Build Coastguard Worker virtual HRESULT STDMETHODCALLTYPE
CreateStreamFromKey(void const * fontFileReferenceKey,uint32_t fontFileReferenceKeySize,OUT IDWriteFontFileStream ** fontFileStream)77*2d1272b8SAndroid Build Coastguard Worker CreateStreamFromKey (void const* fontFileReferenceKey,
78*2d1272b8SAndroid Build Coastguard Worker uint32_t fontFileReferenceKeySize,
79*2d1272b8SAndroid Build Coastguard Worker OUT IDWriteFontFileStream** fontFileStream)
80*2d1272b8SAndroid Build Coastguard Worker {
81*2d1272b8SAndroid Build Coastguard Worker *fontFileStream = mFontFileStream;
82*2d1272b8SAndroid Build Coastguard Worker return S_OK;
83*2d1272b8SAndroid Build Coastguard Worker }
84*2d1272b8SAndroid Build Coastguard Worker
~DWriteFontFileLoader()85*2d1272b8SAndroid Build Coastguard Worker virtual ~DWriteFontFileLoader() {}
86*2d1272b8SAndroid Build Coastguard Worker };
87*2d1272b8SAndroid Build Coastguard Worker
88*2d1272b8SAndroid Build Coastguard Worker class DWriteFontFileStream : public IDWriteFontFileStream
89*2d1272b8SAndroid Build Coastguard Worker {
90*2d1272b8SAndroid Build Coastguard Worker private:
91*2d1272b8SAndroid Build Coastguard Worker uint8_t *mData;
92*2d1272b8SAndroid Build Coastguard Worker uint32_t mSize;
93*2d1272b8SAndroid Build Coastguard Worker public:
DWriteFontFileStream(uint8_t * aData,uint32_t aSize)94*2d1272b8SAndroid Build Coastguard Worker DWriteFontFileStream (uint8_t *aData, uint32_t aSize)
95*2d1272b8SAndroid Build Coastguard Worker {
96*2d1272b8SAndroid Build Coastguard Worker mData = aData;
97*2d1272b8SAndroid Build Coastguard Worker mSize = aSize;
98*2d1272b8SAndroid Build Coastguard Worker }
99*2d1272b8SAndroid Build Coastguard Worker
100*2d1272b8SAndroid Build Coastguard Worker // IUnknown interface
IFACEMETHOD(QueryInterface)101*2d1272b8SAndroid Build Coastguard Worker IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
102*2d1272b8SAndroid Build Coastguard Worker { return S_OK; }
IFACEMETHOD_(ULONG,AddRef)103*2d1272b8SAndroid Build Coastguard Worker IFACEMETHOD_ (ULONG, AddRef) () { return 1; }
IFACEMETHOD_(ULONG,Release)104*2d1272b8SAndroid Build Coastguard Worker IFACEMETHOD_ (ULONG, Release) () { return 1; }
105*2d1272b8SAndroid Build Coastguard Worker
106*2d1272b8SAndroid Build Coastguard Worker // IDWriteFontFileStream methods
107*2d1272b8SAndroid Build Coastguard Worker virtual HRESULT STDMETHODCALLTYPE
ReadFileFragment(void const ** fragmentStart,UINT64 fileOffset,UINT64 fragmentSize,OUT void ** fragmentContext)108*2d1272b8SAndroid Build Coastguard Worker ReadFileFragment (void const** fragmentStart,
109*2d1272b8SAndroid Build Coastguard Worker UINT64 fileOffset,
110*2d1272b8SAndroid Build Coastguard Worker UINT64 fragmentSize,
111*2d1272b8SAndroid Build Coastguard Worker OUT void** fragmentContext)
112*2d1272b8SAndroid Build Coastguard Worker {
113*2d1272b8SAndroid Build Coastguard Worker // We are required to do bounds checking.
114*2d1272b8SAndroid Build Coastguard Worker if (fileOffset + fragmentSize > mSize) return E_FAIL;
115*2d1272b8SAndroid Build Coastguard Worker
116*2d1272b8SAndroid Build Coastguard Worker // truncate the 64 bit fileOffset to size_t sized index into mData
117*2d1272b8SAndroid Build Coastguard Worker size_t index = static_cast<size_t> (fileOffset);
118*2d1272b8SAndroid Build Coastguard Worker
119*2d1272b8SAndroid Build Coastguard Worker // We should be alive for the duration of this.
120*2d1272b8SAndroid Build Coastguard Worker *fragmentStart = &mData[index];
121*2d1272b8SAndroid Build Coastguard Worker *fragmentContext = nullptr;
122*2d1272b8SAndroid Build Coastguard Worker return S_OK;
123*2d1272b8SAndroid Build Coastguard Worker }
124*2d1272b8SAndroid Build Coastguard Worker
125*2d1272b8SAndroid Build Coastguard Worker virtual void STDMETHODCALLTYPE
ReleaseFileFragment(void * fragmentContext)126*2d1272b8SAndroid Build Coastguard Worker ReleaseFileFragment (void* fragmentContext) {}
127*2d1272b8SAndroid Build Coastguard Worker
128*2d1272b8SAndroid Build Coastguard Worker virtual HRESULT STDMETHODCALLTYPE
GetFileSize(OUT UINT64 * fileSize)129*2d1272b8SAndroid Build Coastguard Worker GetFileSize (OUT UINT64* fileSize)
130*2d1272b8SAndroid Build Coastguard Worker {
131*2d1272b8SAndroid Build Coastguard Worker *fileSize = mSize;
132*2d1272b8SAndroid Build Coastguard Worker return S_OK;
133*2d1272b8SAndroid Build Coastguard Worker }
134*2d1272b8SAndroid Build Coastguard Worker
135*2d1272b8SAndroid Build Coastguard Worker virtual HRESULT STDMETHODCALLTYPE
GetLastWriteTime(OUT UINT64 * lastWriteTime)136*2d1272b8SAndroid Build Coastguard Worker GetLastWriteTime (OUT UINT64* lastWriteTime) { return E_NOTIMPL; }
137*2d1272b8SAndroid Build Coastguard Worker
~DWriteFontFileStream()138*2d1272b8SAndroid Build Coastguard Worker virtual ~DWriteFontFileStream() {}
139*2d1272b8SAndroid Build Coastguard Worker };
140*2d1272b8SAndroid Build Coastguard Worker
141*2d1272b8SAndroid Build Coastguard Worker
142*2d1272b8SAndroid Build Coastguard Worker /*
143*2d1272b8SAndroid Build Coastguard Worker * shaper face data
144*2d1272b8SAndroid Build Coastguard Worker */
145*2d1272b8SAndroid Build Coastguard Worker
146*2d1272b8SAndroid Build Coastguard Worker struct hb_directwrite_face_data_t
147*2d1272b8SAndroid Build Coastguard Worker {
148*2d1272b8SAndroid Build Coastguard Worker HMODULE dwrite_dll;
149*2d1272b8SAndroid Build Coastguard Worker IDWriteFactory *dwriteFactory;
150*2d1272b8SAndroid Build Coastguard Worker IDWriteFontFile *fontFile;
151*2d1272b8SAndroid Build Coastguard Worker DWriteFontFileStream *fontFileStream;
152*2d1272b8SAndroid Build Coastguard Worker DWriteFontFileLoader *fontFileLoader;
153*2d1272b8SAndroid Build Coastguard Worker IDWriteFontFace *fontFace;
154*2d1272b8SAndroid Build Coastguard Worker hb_blob_t *faceBlob;
155*2d1272b8SAndroid Build Coastguard Worker };
156*2d1272b8SAndroid Build Coastguard Worker
157*2d1272b8SAndroid Build Coastguard Worker hb_directwrite_face_data_t *
_hb_directwrite_shaper_face_data_create(hb_face_t * face)158*2d1272b8SAndroid Build Coastguard Worker _hb_directwrite_shaper_face_data_create (hb_face_t *face)
159*2d1272b8SAndroid Build Coastguard Worker {
160*2d1272b8SAndroid Build Coastguard Worker hb_directwrite_face_data_t *data = new hb_directwrite_face_data_t;
161*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!data))
162*2d1272b8SAndroid Build Coastguard Worker return nullptr;
163*2d1272b8SAndroid Build Coastguard Worker
164*2d1272b8SAndroid Build Coastguard Worker #define FAIL(...) \
165*2d1272b8SAndroid Build Coastguard Worker HB_STMT_START { \
166*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
167*2d1272b8SAndroid Build Coastguard Worker return nullptr; \
168*2d1272b8SAndroid Build Coastguard Worker } HB_STMT_END
169*2d1272b8SAndroid Build Coastguard Worker
170*2d1272b8SAndroid Build Coastguard Worker data->dwrite_dll = LoadLibrary (TEXT ("DWRITE"));
171*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!data->dwrite_dll))
172*2d1272b8SAndroid Build Coastguard Worker FAIL ("Cannot find DWrite.DLL");
173*2d1272b8SAndroid Build Coastguard Worker
174*2d1272b8SAndroid Build Coastguard Worker t_DWriteCreateFactory p_DWriteCreateFactory;
175*2d1272b8SAndroid Build Coastguard Worker
176*2d1272b8SAndroid Build Coastguard Worker #if defined(__GNUC__) || defined(__clang__)
177*2d1272b8SAndroid Build Coastguard Worker #pragma GCC diagnostic push
178*2d1272b8SAndroid Build Coastguard Worker #pragma GCC diagnostic ignored "-Wcast-function-type"
179*2d1272b8SAndroid Build Coastguard Worker #endif
180*2d1272b8SAndroid Build Coastguard Worker
181*2d1272b8SAndroid Build Coastguard Worker p_DWriteCreateFactory = (t_DWriteCreateFactory)
182*2d1272b8SAndroid Build Coastguard Worker GetProcAddress (data->dwrite_dll, "DWriteCreateFactory");
183*2d1272b8SAndroid Build Coastguard Worker
184*2d1272b8SAndroid Build Coastguard Worker #if defined(__GNUC__) || defined(__clang__)
185*2d1272b8SAndroid Build Coastguard Worker #pragma GCC diagnostic pop
186*2d1272b8SAndroid Build Coastguard Worker #endif
187*2d1272b8SAndroid Build Coastguard Worker
188*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!p_DWriteCreateFactory))
189*2d1272b8SAndroid Build Coastguard Worker FAIL ("Cannot find DWriteCreateFactory().");
190*2d1272b8SAndroid Build Coastguard Worker
191*2d1272b8SAndroid Build Coastguard Worker HRESULT hr;
192*2d1272b8SAndroid Build Coastguard Worker
193*2d1272b8SAndroid Build Coastguard Worker // TODO: factory and fontFileLoader should be cached separately
194*2d1272b8SAndroid Build Coastguard Worker IDWriteFactory* dwriteFactory;
195*2d1272b8SAndroid Build Coastguard Worker hr = p_DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
196*2d1272b8SAndroid Build Coastguard Worker (IUnknown**) &dwriteFactory);
197*2d1272b8SAndroid Build Coastguard Worker
198*2d1272b8SAndroid Build Coastguard Worker if (unlikely (hr != S_OK))
199*2d1272b8SAndroid Build Coastguard Worker FAIL ("Failed to run DWriteCreateFactory().");
200*2d1272b8SAndroid Build Coastguard Worker
201*2d1272b8SAndroid Build Coastguard Worker hb_blob_t *blob = hb_face_reference_blob (face);
202*2d1272b8SAndroid Build Coastguard Worker DWriteFontFileStream *fontFileStream;
203*2d1272b8SAndroid Build Coastguard Worker fontFileStream = new DWriteFontFileStream ((uint8_t *) hb_blob_get_data (blob, nullptr),
204*2d1272b8SAndroid Build Coastguard Worker hb_blob_get_length (blob));
205*2d1272b8SAndroid Build Coastguard Worker
206*2d1272b8SAndroid Build Coastguard Worker DWriteFontFileLoader *fontFileLoader = new DWriteFontFileLoader (fontFileStream);
207*2d1272b8SAndroid Build Coastguard Worker dwriteFactory->RegisterFontFileLoader (fontFileLoader);
208*2d1272b8SAndroid Build Coastguard Worker
209*2d1272b8SAndroid Build Coastguard Worker IDWriteFontFile *fontFile;
210*2d1272b8SAndroid Build Coastguard Worker uint64_t fontFileKey = 0;
211*2d1272b8SAndroid Build Coastguard Worker hr = dwriteFactory->CreateCustomFontFileReference (&fontFileKey, sizeof (fontFileKey),
212*2d1272b8SAndroid Build Coastguard Worker fontFileLoader, &fontFile);
213*2d1272b8SAndroid Build Coastguard Worker
214*2d1272b8SAndroid Build Coastguard Worker if (FAILED (hr))
215*2d1272b8SAndroid Build Coastguard Worker FAIL ("Failed to load font file from data!");
216*2d1272b8SAndroid Build Coastguard Worker
217*2d1272b8SAndroid Build Coastguard Worker BOOL isSupported;
218*2d1272b8SAndroid Build Coastguard Worker DWRITE_FONT_FILE_TYPE fileType;
219*2d1272b8SAndroid Build Coastguard Worker DWRITE_FONT_FACE_TYPE faceType;
220*2d1272b8SAndroid Build Coastguard Worker uint32_t numberOfFaces;
221*2d1272b8SAndroid Build Coastguard Worker hr = fontFile->Analyze (&isSupported, &fileType, &faceType, &numberOfFaces);
222*2d1272b8SAndroid Build Coastguard Worker if (FAILED (hr) || !isSupported)
223*2d1272b8SAndroid Build Coastguard Worker FAIL ("Font file is not supported.");
224*2d1272b8SAndroid Build Coastguard Worker
225*2d1272b8SAndroid Build Coastguard Worker #undef FAIL
226*2d1272b8SAndroid Build Coastguard Worker
227*2d1272b8SAndroid Build Coastguard Worker IDWriteFontFace *fontFace;
228*2d1272b8SAndroid Build Coastguard Worker dwriteFactory->CreateFontFace (faceType, 1, &fontFile, 0,
229*2d1272b8SAndroid Build Coastguard Worker DWRITE_FONT_SIMULATIONS_NONE, &fontFace);
230*2d1272b8SAndroid Build Coastguard Worker
231*2d1272b8SAndroid Build Coastguard Worker data->dwriteFactory = dwriteFactory;
232*2d1272b8SAndroid Build Coastguard Worker data->fontFile = fontFile;
233*2d1272b8SAndroid Build Coastguard Worker data->fontFileStream = fontFileStream;
234*2d1272b8SAndroid Build Coastguard Worker data->fontFileLoader = fontFileLoader;
235*2d1272b8SAndroid Build Coastguard Worker data->fontFace = fontFace;
236*2d1272b8SAndroid Build Coastguard Worker data->faceBlob = blob;
237*2d1272b8SAndroid Build Coastguard Worker
238*2d1272b8SAndroid Build Coastguard Worker return data;
239*2d1272b8SAndroid Build Coastguard Worker }
240*2d1272b8SAndroid Build Coastguard Worker
241*2d1272b8SAndroid Build Coastguard Worker void
_hb_directwrite_shaper_face_data_destroy(hb_directwrite_face_data_t * data)242*2d1272b8SAndroid Build Coastguard Worker _hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data)
243*2d1272b8SAndroid Build Coastguard Worker {
244*2d1272b8SAndroid Build Coastguard Worker if (data->fontFace)
245*2d1272b8SAndroid Build Coastguard Worker data->fontFace->Release ();
246*2d1272b8SAndroid Build Coastguard Worker if (data->fontFile)
247*2d1272b8SAndroid Build Coastguard Worker data->fontFile->Release ();
248*2d1272b8SAndroid Build Coastguard Worker if (data->dwriteFactory)
249*2d1272b8SAndroid Build Coastguard Worker {
250*2d1272b8SAndroid Build Coastguard Worker if (data->fontFileLoader)
251*2d1272b8SAndroid Build Coastguard Worker data->dwriteFactory->UnregisterFontFileLoader (data->fontFileLoader);
252*2d1272b8SAndroid Build Coastguard Worker data->dwriteFactory->Release ();
253*2d1272b8SAndroid Build Coastguard Worker }
254*2d1272b8SAndroid Build Coastguard Worker delete data->fontFileLoader;
255*2d1272b8SAndroid Build Coastguard Worker delete data->fontFileStream;
256*2d1272b8SAndroid Build Coastguard Worker hb_blob_destroy (data->faceBlob);
257*2d1272b8SAndroid Build Coastguard Worker if (data->dwrite_dll)
258*2d1272b8SAndroid Build Coastguard Worker FreeLibrary (data->dwrite_dll);
259*2d1272b8SAndroid Build Coastguard Worker delete data;
260*2d1272b8SAndroid Build Coastguard Worker }
261*2d1272b8SAndroid Build Coastguard Worker
262*2d1272b8SAndroid Build Coastguard Worker
263*2d1272b8SAndroid Build Coastguard Worker /*
264*2d1272b8SAndroid Build Coastguard Worker * shaper font data
265*2d1272b8SAndroid Build Coastguard Worker */
266*2d1272b8SAndroid Build Coastguard Worker
267*2d1272b8SAndroid Build Coastguard Worker struct hb_directwrite_font_data_t {};
268*2d1272b8SAndroid Build Coastguard Worker
269*2d1272b8SAndroid Build Coastguard Worker hb_directwrite_font_data_t *
_hb_directwrite_shaper_font_data_create(hb_font_t * font)270*2d1272b8SAndroid Build Coastguard Worker _hb_directwrite_shaper_font_data_create (hb_font_t *font)
271*2d1272b8SAndroid Build Coastguard Worker {
272*2d1272b8SAndroid Build Coastguard Worker return (hb_directwrite_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
273*2d1272b8SAndroid Build Coastguard Worker }
274*2d1272b8SAndroid Build Coastguard Worker
275*2d1272b8SAndroid Build Coastguard Worker void
_hb_directwrite_shaper_font_data_destroy(hb_directwrite_font_data_t * data)276*2d1272b8SAndroid Build Coastguard Worker _hb_directwrite_shaper_font_data_destroy (hb_directwrite_font_data_t *data)
277*2d1272b8SAndroid Build Coastguard Worker {
278*2d1272b8SAndroid Build Coastguard Worker }
279*2d1272b8SAndroid Build Coastguard Worker
280*2d1272b8SAndroid Build Coastguard Worker
281*2d1272b8SAndroid Build Coastguard Worker // Most of TextAnalysis is originally written by Bas Schouten for Mozilla project
282*2d1272b8SAndroid Build Coastguard Worker // but now is relicensed to MIT for HarfBuzz use
283*2d1272b8SAndroid Build Coastguard Worker class TextAnalysis : public IDWriteTextAnalysisSource, public IDWriteTextAnalysisSink
284*2d1272b8SAndroid Build Coastguard Worker {
285*2d1272b8SAndroid Build Coastguard Worker public:
286*2d1272b8SAndroid Build Coastguard Worker
IFACEMETHOD(QueryInterface)287*2d1272b8SAndroid Build Coastguard Worker IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
288*2d1272b8SAndroid Build Coastguard Worker { return S_OK; }
IFACEMETHOD_(ULONG,AddRef)289*2d1272b8SAndroid Build Coastguard Worker IFACEMETHOD_ (ULONG, AddRef) () { return 1; }
IFACEMETHOD_(ULONG,Release)290*2d1272b8SAndroid Build Coastguard Worker IFACEMETHOD_ (ULONG, Release) () { return 1; }
291*2d1272b8SAndroid Build Coastguard Worker
292*2d1272b8SAndroid Build Coastguard Worker // A single contiguous run of characters containing the same analysis
293*2d1272b8SAndroid Build Coastguard Worker // results.
294*2d1272b8SAndroid Build Coastguard Worker struct Run
295*2d1272b8SAndroid Build Coastguard Worker {
296*2d1272b8SAndroid Build Coastguard Worker uint32_t mTextStart; // starting text position of this run
297*2d1272b8SAndroid Build Coastguard Worker uint32_t mTextLength; // number of contiguous code units covered
298*2d1272b8SAndroid Build Coastguard Worker uint32_t mGlyphStart; // starting glyph in the glyphs array
299*2d1272b8SAndroid Build Coastguard Worker uint32_t mGlyphCount; // number of glyphs associated with this run
300*2d1272b8SAndroid Build Coastguard Worker // text
301*2d1272b8SAndroid Build Coastguard Worker DWRITE_SCRIPT_ANALYSIS mScript;
302*2d1272b8SAndroid Build Coastguard Worker uint8_t mBidiLevel;
303*2d1272b8SAndroid Build Coastguard Worker bool mIsSideways;
304*2d1272b8SAndroid Build Coastguard Worker
ContainsTextPositionTextAnalysis::Run305*2d1272b8SAndroid Build Coastguard Worker bool ContainsTextPosition (uint32_t aTextPosition) const
306*2d1272b8SAndroid Build Coastguard Worker {
307*2d1272b8SAndroid Build Coastguard Worker return aTextPosition >= mTextStart &&
308*2d1272b8SAndroid Build Coastguard Worker aTextPosition < mTextStart + mTextLength;
309*2d1272b8SAndroid Build Coastguard Worker }
310*2d1272b8SAndroid Build Coastguard Worker
311*2d1272b8SAndroid Build Coastguard Worker Run *nextRun;
312*2d1272b8SAndroid Build Coastguard Worker };
313*2d1272b8SAndroid Build Coastguard Worker
314*2d1272b8SAndroid Build Coastguard Worker public:
TextAnalysis(const wchar_t * text,uint32_t textLength,const wchar_t * localeName,DWRITE_READING_DIRECTION readingDirection)315*2d1272b8SAndroid Build Coastguard Worker TextAnalysis (const wchar_t* text, uint32_t textLength,
316*2d1272b8SAndroid Build Coastguard Worker const wchar_t* localeName, DWRITE_READING_DIRECTION readingDirection)
317*2d1272b8SAndroid Build Coastguard Worker : mTextLength (textLength), mText (text), mLocaleName (localeName),
318*2d1272b8SAndroid Build Coastguard Worker mReadingDirection (readingDirection), mCurrentRun (nullptr) {}
~TextAnalysis()319*2d1272b8SAndroid Build Coastguard Worker ~TextAnalysis ()
320*2d1272b8SAndroid Build Coastguard Worker {
321*2d1272b8SAndroid Build Coastguard Worker // delete runs, except mRunHead which is part of the TextAnalysis object
322*2d1272b8SAndroid Build Coastguard Worker for (Run *run = mRunHead.nextRun; run;)
323*2d1272b8SAndroid Build Coastguard Worker {
324*2d1272b8SAndroid Build Coastguard Worker Run *origRun = run;
325*2d1272b8SAndroid Build Coastguard Worker run = run->nextRun;
326*2d1272b8SAndroid Build Coastguard Worker delete origRun;
327*2d1272b8SAndroid Build Coastguard Worker }
328*2d1272b8SAndroid Build Coastguard Worker }
329*2d1272b8SAndroid Build Coastguard Worker
330*2d1272b8SAndroid Build Coastguard Worker STDMETHODIMP
GenerateResults(IDWriteTextAnalyzer * textAnalyzer,Run ** runHead)331*2d1272b8SAndroid Build Coastguard Worker GenerateResults (IDWriteTextAnalyzer* textAnalyzer, Run **runHead)
332*2d1272b8SAndroid Build Coastguard Worker {
333*2d1272b8SAndroid Build Coastguard Worker // Analyzes the text using the script analyzer and returns
334*2d1272b8SAndroid Build Coastguard Worker // the result as a series of runs.
335*2d1272b8SAndroid Build Coastguard Worker
336*2d1272b8SAndroid Build Coastguard Worker HRESULT hr = S_OK;
337*2d1272b8SAndroid Build Coastguard Worker
338*2d1272b8SAndroid Build Coastguard Worker // Initially start out with one result that covers the entire range.
339*2d1272b8SAndroid Build Coastguard Worker // This result will be subdivided by the analysis processes.
340*2d1272b8SAndroid Build Coastguard Worker mRunHead.mTextStart = 0;
341*2d1272b8SAndroid Build Coastguard Worker mRunHead.mTextLength = mTextLength;
342*2d1272b8SAndroid Build Coastguard Worker mRunHead.mBidiLevel =
343*2d1272b8SAndroid Build Coastguard Worker (mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
344*2d1272b8SAndroid Build Coastguard Worker mRunHead.nextRun = nullptr;
345*2d1272b8SAndroid Build Coastguard Worker mCurrentRun = &mRunHead;
346*2d1272b8SAndroid Build Coastguard Worker
347*2d1272b8SAndroid Build Coastguard Worker // Call each of the analyzers in sequence, recording their results.
348*2d1272b8SAndroid Build Coastguard Worker if (SUCCEEDED (hr = textAnalyzer->AnalyzeScript (this, 0, mTextLength, this)))
349*2d1272b8SAndroid Build Coastguard Worker *runHead = &mRunHead;
350*2d1272b8SAndroid Build Coastguard Worker
351*2d1272b8SAndroid Build Coastguard Worker return hr;
352*2d1272b8SAndroid Build Coastguard Worker }
353*2d1272b8SAndroid Build Coastguard Worker
354*2d1272b8SAndroid Build Coastguard Worker // IDWriteTextAnalysisSource implementation
355*2d1272b8SAndroid Build Coastguard Worker
356*2d1272b8SAndroid Build Coastguard Worker IFACEMETHODIMP
GetTextAtPosition(uint32_t textPosition,OUT wchar_t const ** textString,OUT uint32_t * textLength)357*2d1272b8SAndroid Build Coastguard Worker GetTextAtPosition (uint32_t textPosition,
358*2d1272b8SAndroid Build Coastguard Worker OUT wchar_t const** textString,
359*2d1272b8SAndroid Build Coastguard Worker OUT uint32_t* textLength)
360*2d1272b8SAndroid Build Coastguard Worker {
361*2d1272b8SAndroid Build Coastguard Worker if (textPosition >= mTextLength)
362*2d1272b8SAndroid Build Coastguard Worker {
363*2d1272b8SAndroid Build Coastguard Worker // No text at this position, valid query though.
364*2d1272b8SAndroid Build Coastguard Worker *textString = nullptr;
365*2d1272b8SAndroid Build Coastguard Worker *textLength = 0;
366*2d1272b8SAndroid Build Coastguard Worker }
367*2d1272b8SAndroid Build Coastguard Worker else
368*2d1272b8SAndroid Build Coastguard Worker {
369*2d1272b8SAndroid Build Coastguard Worker *textString = mText + textPosition;
370*2d1272b8SAndroid Build Coastguard Worker *textLength = mTextLength - textPosition;
371*2d1272b8SAndroid Build Coastguard Worker }
372*2d1272b8SAndroid Build Coastguard Worker return S_OK;
373*2d1272b8SAndroid Build Coastguard Worker }
374*2d1272b8SAndroid Build Coastguard Worker
375*2d1272b8SAndroid Build Coastguard Worker IFACEMETHODIMP
GetTextBeforePosition(uint32_t textPosition,OUT wchar_t const ** textString,OUT uint32_t * textLength)376*2d1272b8SAndroid Build Coastguard Worker GetTextBeforePosition (uint32_t textPosition,
377*2d1272b8SAndroid Build Coastguard Worker OUT wchar_t const** textString,
378*2d1272b8SAndroid Build Coastguard Worker OUT uint32_t* textLength)
379*2d1272b8SAndroid Build Coastguard Worker {
380*2d1272b8SAndroid Build Coastguard Worker if (textPosition == 0 || textPosition > mTextLength)
381*2d1272b8SAndroid Build Coastguard Worker {
382*2d1272b8SAndroid Build Coastguard Worker // Either there is no text before here (== 0), or this
383*2d1272b8SAndroid Build Coastguard Worker // is an invalid position. The query is considered valid though.
384*2d1272b8SAndroid Build Coastguard Worker *textString = nullptr;
385*2d1272b8SAndroid Build Coastguard Worker *textLength = 0;
386*2d1272b8SAndroid Build Coastguard Worker }
387*2d1272b8SAndroid Build Coastguard Worker else
388*2d1272b8SAndroid Build Coastguard Worker {
389*2d1272b8SAndroid Build Coastguard Worker *textString = mText;
390*2d1272b8SAndroid Build Coastguard Worker *textLength = textPosition;
391*2d1272b8SAndroid Build Coastguard Worker }
392*2d1272b8SAndroid Build Coastguard Worker return S_OK;
393*2d1272b8SAndroid Build Coastguard Worker }
394*2d1272b8SAndroid Build Coastguard Worker
395*2d1272b8SAndroid Build Coastguard Worker IFACEMETHODIMP_ (DWRITE_READING_DIRECTION)
GetParagraphReadingDirection()396*2d1272b8SAndroid Build Coastguard Worker GetParagraphReadingDirection () { return mReadingDirection; }
397*2d1272b8SAndroid Build Coastguard Worker
GetLocaleName(uint32_t textPosition,uint32_t * textLength,wchar_t const ** localeName)398*2d1272b8SAndroid Build Coastguard Worker IFACEMETHODIMP GetLocaleName (uint32_t textPosition, uint32_t* textLength,
399*2d1272b8SAndroid Build Coastguard Worker wchar_t const** localeName)
400*2d1272b8SAndroid Build Coastguard Worker { return S_OK; }
401*2d1272b8SAndroid Build Coastguard Worker
402*2d1272b8SAndroid Build Coastguard Worker IFACEMETHODIMP
GetNumberSubstitution(uint32_t textPosition,OUT uint32_t * textLength,OUT IDWriteNumberSubstitution ** numberSubstitution)403*2d1272b8SAndroid Build Coastguard Worker GetNumberSubstitution (uint32_t textPosition,
404*2d1272b8SAndroid Build Coastguard Worker OUT uint32_t* textLength,
405*2d1272b8SAndroid Build Coastguard Worker OUT IDWriteNumberSubstitution** numberSubstitution)
406*2d1272b8SAndroid Build Coastguard Worker {
407*2d1272b8SAndroid Build Coastguard Worker // We do not support number substitution.
408*2d1272b8SAndroid Build Coastguard Worker *numberSubstitution = nullptr;
409*2d1272b8SAndroid Build Coastguard Worker *textLength = mTextLength - textPosition;
410*2d1272b8SAndroid Build Coastguard Worker
411*2d1272b8SAndroid Build Coastguard Worker return S_OK;
412*2d1272b8SAndroid Build Coastguard Worker }
413*2d1272b8SAndroid Build Coastguard Worker
414*2d1272b8SAndroid Build Coastguard Worker // IDWriteTextAnalysisSink implementation
415*2d1272b8SAndroid Build Coastguard Worker
416*2d1272b8SAndroid Build Coastguard Worker IFACEMETHODIMP
SetScriptAnalysis(uint32_t textPosition,uint32_t textLength,DWRITE_SCRIPT_ANALYSIS const * scriptAnalysis)417*2d1272b8SAndroid Build Coastguard Worker SetScriptAnalysis (uint32_t textPosition, uint32_t textLength,
418*2d1272b8SAndroid Build Coastguard Worker DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis)
419*2d1272b8SAndroid Build Coastguard Worker {
420*2d1272b8SAndroid Build Coastguard Worker SetCurrentRun (textPosition);
421*2d1272b8SAndroid Build Coastguard Worker SplitCurrentRun (textPosition);
422*2d1272b8SAndroid Build Coastguard Worker while (textLength > 0)
423*2d1272b8SAndroid Build Coastguard Worker {
424*2d1272b8SAndroid Build Coastguard Worker Run *run = FetchNextRun (&textLength);
425*2d1272b8SAndroid Build Coastguard Worker run->mScript = *scriptAnalysis;
426*2d1272b8SAndroid Build Coastguard Worker }
427*2d1272b8SAndroid Build Coastguard Worker
428*2d1272b8SAndroid Build Coastguard Worker return S_OK;
429*2d1272b8SAndroid Build Coastguard Worker }
430*2d1272b8SAndroid Build Coastguard Worker
431*2d1272b8SAndroid Build Coastguard Worker IFACEMETHODIMP
SetLineBreakpoints(uint32_t textPosition,uint32_t textLength,const DWRITE_LINE_BREAKPOINT * lineBreakpoints)432*2d1272b8SAndroid Build Coastguard Worker SetLineBreakpoints (uint32_t textPosition,
433*2d1272b8SAndroid Build Coastguard Worker uint32_t textLength,
434*2d1272b8SAndroid Build Coastguard Worker const DWRITE_LINE_BREAKPOINT* lineBreakpoints)
435*2d1272b8SAndroid Build Coastguard Worker { return S_OK; }
436*2d1272b8SAndroid Build Coastguard Worker
SetBidiLevel(uint32_t textPosition,uint32_t textLength,uint8_t explicitLevel,uint8_t resolvedLevel)437*2d1272b8SAndroid Build Coastguard Worker IFACEMETHODIMP SetBidiLevel (uint32_t textPosition, uint32_t textLength,
438*2d1272b8SAndroid Build Coastguard Worker uint8_t explicitLevel, uint8_t resolvedLevel)
439*2d1272b8SAndroid Build Coastguard Worker { return S_OK; }
440*2d1272b8SAndroid Build Coastguard Worker
441*2d1272b8SAndroid Build Coastguard Worker IFACEMETHODIMP
SetNumberSubstitution(uint32_t textPosition,uint32_t textLength,IDWriteNumberSubstitution * numberSubstitution)442*2d1272b8SAndroid Build Coastguard Worker SetNumberSubstitution (uint32_t textPosition, uint32_t textLength,
443*2d1272b8SAndroid Build Coastguard Worker IDWriteNumberSubstitution* numberSubstitution)
444*2d1272b8SAndroid Build Coastguard Worker { return S_OK; }
445*2d1272b8SAndroid Build Coastguard Worker
446*2d1272b8SAndroid Build Coastguard Worker protected:
FetchNextRun(IN OUT uint32_t * textLength)447*2d1272b8SAndroid Build Coastguard Worker Run *FetchNextRun (IN OUT uint32_t* textLength)
448*2d1272b8SAndroid Build Coastguard Worker {
449*2d1272b8SAndroid Build Coastguard Worker // Used by the sink setters, this returns a reference to the next run.
450*2d1272b8SAndroid Build Coastguard Worker // Position and length are adjusted to now point after the current run
451*2d1272b8SAndroid Build Coastguard Worker // being returned.
452*2d1272b8SAndroid Build Coastguard Worker
453*2d1272b8SAndroid Build Coastguard Worker Run *origRun = mCurrentRun;
454*2d1272b8SAndroid Build Coastguard Worker // Split the tail if needed (the length remaining is less than the
455*2d1272b8SAndroid Build Coastguard Worker // current run's size).
456*2d1272b8SAndroid Build Coastguard Worker if (*textLength < mCurrentRun->mTextLength)
457*2d1272b8SAndroid Build Coastguard Worker SplitCurrentRun (mCurrentRun->mTextStart + *textLength);
458*2d1272b8SAndroid Build Coastguard Worker else
459*2d1272b8SAndroid Build Coastguard Worker // Just advance the current run.
460*2d1272b8SAndroid Build Coastguard Worker mCurrentRun = mCurrentRun->nextRun;
461*2d1272b8SAndroid Build Coastguard Worker *textLength -= origRun->mTextLength;
462*2d1272b8SAndroid Build Coastguard Worker
463*2d1272b8SAndroid Build Coastguard Worker // Return a reference to the run that was just current.
464*2d1272b8SAndroid Build Coastguard Worker return origRun;
465*2d1272b8SAndroid Build Coastguard Worker }
466*2d1272b8SAndroid Build Coastguard Worker
SetCurrentRun(uint32_t textPosition)467*2d1272b8SAndroid Build Coastguard Worker void SetCurrentRun (uint32_t textPosition)
468*2d1272b8SAndroid Build Coastguard Worker {
469*2d1272b8SAndroid Build Coastguard Worker // Move the current run to the given position.
470*2d1272b8SAndroid Build Coastguard Worker // Since the analyzers generally return results in a forward manner,
471*2d1272b8SAndroid Build Coastguard Worker // this will usually just return early. If not, find the
472*2d1272b8SAndroid Build Coastguard Worker // corresponding run for the text position.
473*2d1272b8SAndroid Build Coastguard Worker
474*2d1272b8SAndroid Build Coastguard Worker if (mCurrentRun && mCurrentRun->ContainsTextPosition (textPosition))
475*2d1272b8SAndroid Build Coastguard Worker return;
476*2d1272b8SAndroid Build Coastguard Worker
477*2d1272b8SAndroid Build Coastguard Worker for (Run *run = &mRunHead; run; run = run->nextRun)
478*2d1272b8SAndroid Build Coastguard Worker if (run->ContainsTextPosition (textPosition))
479*2d1272b8SAndroid Build Coastguard Worker {
480*2d1272b8SAndroid Build Coastguard Worker mCurrentRun = run;
481*2d1272b8SAndroid Build Coastguard Worker return;
482*2d1272b8SAndroid Build Coastguard Worker }
483*2d1272b8SAndroid Build Coastguard Worker assert (0); // We should always be able to find the text position in one of our runs
484*2d1272b8SAndroid Build Coastguard Worker }
485*2d1272b8SAndroid Build Coastguard Worker
SplitCurrentRun(uint32_t splitPosition)486*2d1272b8SAndroid Build Coastguard Worker void SplitCurrentRun (uint32_t splitPosition)
487*2d1272b8SAndroid Build Coastguard Worker {
488*2d1272b8SAndroid Build Coastguard Worker if (!mCurrentRun)
489*2d1272b8SAndroid Build Coastguard Worker {
490*2d1272b8SAndroid Build Coastguard Worker assert (0); // SplitCurrentRun called without current run
491*2d1272b8SAndroid Build Coastguard Worker // Shouldn't be calling this when no current run is set!
492*2d1272b8SAndroid Build Coastguard Worker return;
493*2d1272b8SAndroid Build Coastguard Worker }
494*2d1272b8SAndroid Build Coastguard Worker // Split the current run.
495*2d1272b8SAndroid Build Coastguard Worker if (splitPosition <= mCurrentRun->mTextStart)
496*2d1272b8SAndroid Build Coastguard Worker {
497*2d1272b8SAndroid Build Coastguard Worker // No need to split, already the start of a run
498*2d1272b8SAndroid Build Coastguard Worker // or before it. Usually the first.
499*2d1272b8SAndroid Build Coastguard Worker return;
500*2d1272b8SAndroid Build Coastguard Worker }
501*2d1272b8SAndroid Build Coastguard Worker Run *newRun = new Run;
502*2d1272b8SAndroid Build Coastguard Worker
503*2d1272b8SAndroid Build Coastguard Worker *newRun = *mCurrentRun;
504*2d1272b8SAndroid Build Coastguard Worker
505*2d1272b8SAndroid Build Coastguard Worker // Insert the new run in our linked list.
506*2d1272b8SAndroid Build Coastguard Worker newRun->nextRun = mCurrentRun->nextRun;
507*2d1272b8SAndroid Build Coastguard Worker mCurrentRun->nextRun = newRun;
508*2d1272b8SAndroid Build Coastguard Worker
509*2d1272b8SAndroid Build Coastguard Worker // Adjust runs' text positions and lengths.
510*2d1272b8SAndroid Build Coastguard Worker uint32_t splitPoint = splitPosition - mCurrentRun->mTextStart;
511*2d1272b8SAndroid Build Coastguard Worker newRun->mTextStart += splitPoint;
512*2d1272b8SAndroid Build Coastguard Worker newRun->mTextLength -= splitPoint;
513*2d1272b8SAndroid Build Coastguard Worker mCurrentRun->mTextLength = splitPoint;
514*2d1272b8SAndroid Build Coastguard Worker mCurrentRun = newRun;
515*2d1272b8SAndroid Build Coastguard Worker }
516*2d1272b8SAndroid Build Coastguard Worker
517*2d1272b8SAndroid Build Coastguard Worker protected:
518*2d1272b8SAndroid Build Coastguard Worker // Input
519*2d1272b8SAndroid Build Coastguard Worker // (weak references are fine here, since this class is a transient
520*2d1272b8SAndroid Build Coastguard Worker // stack-based helper that doesn't need to copy data)
521*2d1272b8SAndroid Build Coastguard Worker uint32_t mTextLength;
522*2d1272b8SAndroid Build Coastguard Worker const wchar_t* mText;
523*2d1272b8SAndroid Build Coastguard Worker const wchar_t* mLocaleName;
524*2d1272b8SAndroid Build Coastguard Worker DWRITE_READING_DIRECTION mReadingDirection;
525*2d1272b8SAndroid Build Coastguard Worker
526*2d1272b8SAndroid Build Coastguard Worker // Current processing state.
527*2d1272b8SAndroid Build Coastguard Worker Run *mCurrentRun;
528*2d1272b8SAndroid Build Coastguard Worker
529*2d1272b8SAndroid Build Coastguard Worker // Output is a list of runs starting here
530*2d1272b8SAndroid Build Coastguard Worker Run mRunHead;
531*2d1272b8SAndroid Build Coastguard Worker };
532*2d1272b8SAndroid Build Coastguard Worker
533*2d1272b8SAndroid Build Coastguard Worker /*
534*2d1272b8SAndroid Build Coastguard Worker * shaper
535*2d1272b8SAndroid Build Coastguard Worker */
536*2d1272b8SAndroid Build Coastguard Worker
537*2d1272b8SAndroid Build Coastguard Worker hb_bool_t
_hb_directwrite_shape(hb_shape_plan_t * shape_plan,hb_font_t * font,hb_buffer_t * buffer,const hb_feature_t * features,unsigned int num_features)538*2d1272b8SAndroid Build Coastguard Worker _hb_directwrite_shape (hb_shape_plan_t *shape_plan,
539*2d1272b8SAndroid Build Coastguard Worker hb_font_t *font,
540*2d1272b8SAndroid Build Coastguard Worker hb_buffer_t *buffer,
541*2d1272b8SAndroid Build Coastguard Worker const hb_feature_t *features,
542*2d1272b8SAndroid Build Coastguard Worker unsigned int num_features)
543*2d1272b8SAndroid Build Coastguard Worker {
544*2d1272b8SAndroid Build Coastguard Worker hb_face_t *face = font->face;
545*2d1272b8SAndroid Build Coastguard Worker const hb_directwrite_face_data_t *face_data = face->data.directwrite;
546*2d1272b8SAndroid Build Coastguard Worker IDWriteFactory *dwriteFactory = face_data->dwriteFactory;
547*2d1272b8SAndroid Build Coastguard Worker IDWriteFontFace *fontFace = face_data->fontFace;
548*2d1272b8SAndroid Build Coastguard Worker
549*2d1272b8SAndroid Build Coastguard Worker IDWriteTextAnalyzer* analyzer;
550*2d1272b8SAndroid Build Coastguard Worker dwriteFactory->CreateTextAnalyzer (&analyzer);
551*2d1272b8SAndroid Build Coastguard Worker
552*2d1272b8SAndroid Build Coastguard Worker unsigned int scratch_size;
553*2d1272b8SAndroid Build Coastguard Worker hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
554*2d1272b8SAndroid Build Coastguard Worker #define ALLOCATE_ARRAY(Type, name, len) \
555*2d1272b8SAndroid Build Coastguard Worker Type *name = (Type *) scratch; \
556*2d1272b8SAndroid Build Coastguard Worker do { \
557*2d1272b8SAndroid Build Coastguard Worker unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
558*2d1272b8SAndroid Build Coastguard Worker assert (_consumed <= scratch_size); \
559*2d1272b8SAndroid Build Coastguard Worker scratch += _consumed; \
560*2d1272b8SAndroid Build Coastguard Worker scratch_size -= _consumed; \
561*2d1272b8SAndroid Build Coastguard Worker } while (0)
562*2d1272b8SAndroid Build Coastguard Worker
563*2d1272b8SAndroid Build Coastguard Worker #define utf16_index() var1.u32
564*2d1272b8SAndroid Build Coastguard Worker
565*2d1272b8SAndroid Build Coastguard Worker ALLOCATE_ARRAY (wchar_t, textString, buffer->len * 2);
566*2d1272b8SAndroid Build Coastguard Worker
567*2d1272b8SAndroid Build Coastguard Worker unsigned int chars_len = 0;
568*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < buffer->len; i++)
569*2d1272b8SAndroid Build Coastguard Worker {
570*2d1272b8SAndroid Build Coastguard Worker hb_codepoint_t c = buffer->info[i].codepoint;
571*2d1272b8SAndroid Build Coastguard Worker buffer->info[i].utf16_index () = chars_len;
572*2d1272b8SAndroid Build Coastguard Worker if (likely (c <= 0xFFFFu))
573*2d1272b8SAndroid Build Coastguard Worker textString[chars_len++] = c;
574*2d1272b8SAndroid Build Coastguard Worker else if (unlikely (c > 0x10FFFFu))
575*2d1272b8SAndroid Build Coastguard Worker textString[chars_len++] = 0xFFFDu;
576*2d1272b8SAndroid Build Coastguard Worker else
577*2d1272b8SAndroid Build Coastguard Worker {
578*2d1272b8SAndroid Build Coastguard Worker textString[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
579*2d1272b8SAndroid Build Coastguard Worker textString[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1u << 10) - 1));
580*2d1272b8SAndroid Build Coastguard Worker }
581*2d1272b8SAndroid Build Coastguard Worker }
582*2d1272b8SAndroid Build Coastguard Worker
583*2d1272b8SAndroid Build Coastguard Worker ALLOCATE_ARRAY (WORD, log_clusters, chars_len);
584*2d1272b8SAndroid Build Coastguard Worker /* Need log_clusters to assign features. */
585*2d1272b8SAndroid Build Coastguard Worker chars_len = 0;
586*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < buffer->len; i++)
587*2d1272b8SAndroid Build Coastguard Worker {
588*2d1272b8SAndroid Build Coastguard Worker hb_codepoint_t c = buffer->info[i].codepoint;
589*2d1272b8SAndroid Build Coastguard Worker unsigned int cluster = buffer->info[i].cluster;
590*2d1272b8SAndroid Build Coastguard Worker log_clusters[chars_len++] = cluster;
591*2d1272b8SAndroid Build Coastguard Worker if (hb_in_range (c, 0x10000u, 0x10FFFFu))
592*2d1272b8SAndroid Build Coastguard Worker log_clusters[chars_len++] = cluster; /* Surrogates. */
593*2d1272b8SAndroid Build Coastguard Worker }
594*2d1272b8SAndroid Build Coastguard Worker
595*2d1272b8SAndroid Build Coastguard Worker DWRITE_READING_DIRECTION readingDirection;
596*2d1272b8SAndroid Build Coastguard Worker readingDirection = buffer->props.direction ?
597*2d1272b8SAndroid Build Coastguard Worker DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
598*2d1272b8SAndroid Build Coastguard Worker DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
599*2d1272b8SAndroid Build Coastguard Worker
600*2d1272b8SAndroid Build Coastguard Worker /*
601*2d1272b8SAndroid Build Coastguard Worker * There's an internal 16-bit limit on some things inside the analyzer,
602*2d1272b8SAndroid Build Coastguard Worker * but we never attempt to shape a word longer than 64K characters
603*2d1272b8SAndroid Build Coastguard Worker * in a single gfxShapedWord, so we cannot exceed that limit.
604*2d1272b8SAndroid Build Coastguard Worker */
605*2d1272b8SAndroid Build Coastguard Worker uint32_t textLength = chars_len;
606*2d1272b8SAndroid Build Coastguard Worker
607*2d1272b8SAndroid Build Coastguard Worker TextAnalysis analysis (textString, textLength, nullptr, readingDirection);
608*2d1272b8SAndroid Build Coastguard Worker TextAnalysis::Run *runHead;
609*2d1272b8SAndroid Build Coastguard Worker HRESULT hr;
610*2d1272b8SAndroid Build Coastguard Worker hr = analysis.GenerateResults (analyzer, &runHead);
611*2d1272b8SAndroid Build Coastguard Worker
612*2d1272b8SAndroid Build Coastguard Worker #define FAIL(...) \
613*2d1272b8SAndroid Build Coastguard Worker HB_STMT_START { \
614*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
615*2d1272b8SAndroid Build Coastguard Worker return false; \
616*2d1272b8SAndroid Build Coastguard Worker } HB_STMT_END
617*2d1272b8SAndroid Build Coastguard Worker
618*2d1272b8SAndroid Build Coastguard Worker if (FAILED (hr))
619*2d1272b8SAndroid Build Coastguard Worker FAIL ("Analyzer failed to generate results.");
620*2d1272b8SAndroid Build Coastguard Worker
621*2d1272b8SAndroid Build Coastguard Worker uint32_t maxGlyphCount = 3 * textLength / 2 + 16;
622*2d1272b8SAndroid Build Coastguard Worker uint32_t glyphCount;
623*2d1272b8SAndroid Build Coastguard Worker bool isRightToLeft = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
624*2d1272b8SAndroid Build Coastguard Worker
625*2d1272b8SAndroid Build Coastguard Worker const wchar_t localeName[20] = {0};
626*2d1272b8SAndroid Build Coastguard Worker if (buffer->props.language)
627*2d1272b8SAndroid Build Coastguard Worker mbstowcs ((wchar_t*) localeName,
628*2d1272b8SAndroid Build Coastguard Worker hb_language_to_string (buffer->props.language), 20);
629*2d1272b8SAndroid Build Coastguard Worker
630*2d1272b8SAndroid Build Coastguard Worker /*
631*2d1272b8SAndroid Build Coastguard Worker * Set up features.
632*2d1272b8SAndroid Build Coastguard Worker */
633*2d1272b8SAndroid Build Coastguard Worker static_assert ((sizeof (DWRITE_TYPOGRAPHIC_FEATURES) == sizeof (hb_ms_features_t)), "");
634*2d1272b8SAndroid Build Coastguard Worker static_assert ((sizeof (DWRITE_FONT_FEATURE) == sizeof (hb_ms_feature_t)), "");
635*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<hb_ms_features_t *> range_features;
636*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<uint32_t> range_char_counts;
637*2d1272b8SAndroid Build Coastguard Worker if (num_features)
638*2d1272b8SAndroid Build Coastguard Worker {
639*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<hb_ms_feature_t> feature_records;
640*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<hb_ms_range_record_t> range_records;
641*2d1272b8SAndroid Build Coastguard Worker if (hb_ms_setup_features (features, num_features, feature_records, range_records))
642*2d1272b8SAndroid Build Coastguard Worker hb_ms_make_feature_ranges (feature_records,
643*2d1272b8SAndroid Build Coastguard Worker range_records,
644*2d1272b8SAndroid Build Coastguard Worker 0,
645*2d1272b8SAndroid Build Coastguard Worker chars_len,
646*2d1272b8SAndroid Build Coastguard Worker log_clusters,
647*2d1272b8SAndroid Build Coastguard Worker range_features,
648*2d1272b8SAndroid Build Coastguard Worker range_char_counts);
649*2d1272b8SAndroid Build Coastguard Worker }
650*2d1272b8SAndroid Build Coastguard Worker
651*2d1272b8SAndroid Build Coastguard Worker uint16_t* clusterMap;
652*2d1272b8SAndroid Build Coastguard Worker clusterMap = new uint16_t[textLength];
653*2d1272b8SAndroid Build Coastguard Worker DWRITE_SHAPING_TEXT_PROPERTIES* textProperties;
654*2d1272b8SAndroid Build Coastguard Worker textProperties = new DWRITE_SHAPING_TEXT_PROPERTIES[textLength];
655*2d1272b8SAndroid Build Coastguard Worker
656*2d1272b8SAndroid Build Coastguard Worker retry_getglyphs:
657*2d1272b8SAndroid Build Coastguard Worker uint16_t* glyphIndices = new uint16_t[maxGlyphCount];
658*2d1272b8SAndroid Build Coastguard Worker DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties;
659*2d1272b8SAndroid Build Coastguard Worker glyphProperties = new DWRITE_SHAPING_GLYPH_PROPERTIES[maxGlyphCount];
660*2d1272b8SAndroid Build Coastguard Worker
661*2d1272b8SAndroid Build Coastguard Worker hr = analyzer->GetGlyphs (textString,
662*2d1272b8SAndroid Build Coastguard Worker chars_len,
663*2d1272b8SAndroid Build Coastguard Worker fontFace,
664*2d1272b8SAndroid Build Coastguard Worker false,
665*2d1272b8SAndroid Build Coastguard Worker isRightToLeft,
666*2d1272b8SAndroid Build Coastguard Worker &runHead->mScript,
667*2d1272b8SAndroid Build Coastguard Worker localeName,
668*2d1272b8SAndroid Build Coastguard Worker nullptr,
669*2d1272b8SAndroid Build Coastguard Worker (const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ,
670*2d1272b8SAndroid Build Coastguard Worker range_char_counts.arrayZ,
671*2d1272b8SAndroid Build Coastguard Worker range_features.length,
672*2d1272b8SAndroid Build Coastguard Worker maxGlyphCount,
673*2d1272b8SAndroid Build Coastguard Worker clusterMap,
674*2d1272b8SAndroid Build Coastguard Worker textProperties,
675*2d1272b8SAndroid Build Coastguard Worker glyphIndices,
676*2d1272b8SAndroid Build Coastguard Worker glyphProperties,
677*2d1272b8SAndroid Build Coastguard Worker &glyphCount);
678*2d1272b8SAndroid Build Coastguard Worker
679*2d1272b8SAndroid Build Coastguard Worker if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)))
680*2d1272b8SAndroid Build Coastguard Worker {
681*2d1272b8SAndroid Build Coastguard Worker delete [] glyphIndices;
682*2d1272b8SAndroid Build Coastguard Worker delete [] glyphProperties;
683*2d1272b8SAndroid Build Coastguard Worker
684*2d1272b8SAndroid Build Coastguard Worker maxGlyphCount *= 2;
685*2d1272b8SAndroid Build Coastguard Worker
686*2d1272b8SAndroid Build Coastguard Worker goto retry_getglyphs;
687*2d1272b8SAndroid Build Coastguard Worker }
688*2d1272b8SAndroid Build Coastguard Worker if (FAILED (hr))
689*2d1272b8SAndroid Build Coastguard Worker FAIL ("Analyzer failed to get glyphs.");
690*2d1272b8SAndroid Build Coastguard Worker
691*2d1272b8SAndroid Build Coastguard Worker float* glyphAdvances = new float[maxGlyphCount];
692*2d1272b8SAndroid Build Coastguard Worker DWRITE_GLYPH_OFFSET* glyphOffsets = new DWRITE_GLYPH_OFFSET[maxGlyphCount];
693*2d1272b8SAndroid Build Coastguard Worker
694*2d1272b8SAndroid Build Coastguard Worker /* The -2 in the following is to compensate for possible
695*2d1272b8SAndroid Build Coastguard Worker * alignment needed after the WORD array. sizeof (WORD) == 2. */
696*2d1272b8SAndroid Build Coastguard Worker unsigned int glyphs_size = (scratch_size * sizeof (int) - 2)
697*2d1272b8SAndroid Build Coastguard Worker / (sizeof (WORD) +
698*2d1272b8SAndroid Build Coastguard Worker sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES) +
699*2d1272b8SAndroid Build Coastguard Worker sizeof (int) +
700*2d1272b8SAndroid Build Coastguard Worker sizeof (DWRITE_GLYPH_OFFSET) +
701*2d1272b8SAndroid Build Coastguard Worker sizeof (uint32_t));
702*2d1272b8SAndroid Build Coastguard Worker ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
703*2d1272b8SAndroid Build Coastguard Worker
704*2d1272b8SAndroid Build Coastguard Worker #undef ALLOCATE_ARRAY
705*2d1272b8SAndroid Build Coastguard Worker
706*2d1272b8SAndroid Build Coastguard Worker int fontEmSize = font->face->get_upem ();
707*2d1272b8SAndroid Build Coastguard Worker if (fontEmSize < 0) fontEmSize = -fontEmSize;
708*2d1272b8SAndroid Build Coastguard Worker
709*2d1272b8SAndroid Build Coastguard Worker if (fontEmSize < 0) fontEmSize = -fontEmSize;
710*2d1272b8SAndroid Build Coastguard Worker double x_mult = (double) font->x_scale / fontEmSize;
711*2d1272b8SAndroid Build Coastguard Worker double y_mult = (double) font->y_scale / fontEmSize;
712*2d1272b8SAndroid Build Coastguard Worker
713*2d1272b8SAndroid Build Coastguard Worker hr = analyzer->GetGlyphPlacements (textString,
714*2d1272b8SAndroid Build Coastguard Worker clusterMap,
715*2d1272b8SAndroid Build Coastguard Worker textProperties,
716*2d1272b8SAndroid Build Coastguard Worker chars_len,
717*2d1272b8SAndroid Build Coastguard Worker glyphIndices,
718*2d1272b8SAndroid Build Coastguard Worker glyphProperties,
719*2d1272b8SAndroid Build Coastguard Worker glyphCount,
720*2d1272b8SAndroid Build Coastguard Worker fontFace,
721*2d1272b8SAndroid Build Coastguard Worker fontEmSize,
722*2d1272b8SAndroid Build Coastguard Worker false,
723*2d1272b8SAndroid Build Coastguard Worker isRightToLeft,
724*2d1272b8SAndroid Build Coastguard Worker &runHead->mScript,
725*2d1272b8SAndroid Build Coastguard Worker localeName,
726*2d1272b8SAndroid Build Coastguard Worker (const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ,
727*2d1272b8SAndroid Build Coastguard Worker range_char_counts.arrayZ,
728*2d1272b8SAndroid Build Coastguard Worker range_features.length,
729*2d1272b8SAndroid Build Coastguard Worker glyphAdvances,
730*2d1272b8SAndroid Build Coastguard Worker glyphOffsets);
731*2d1272b8SAndroid Build Coastguard Worker
732*2d1272b8SAndroid Build Coastguard Worker if (FAILED (hr))
733*2d1272b8SAndroid Build Coastguard Worker FAIL ("Analyzer failed to get glyph placements.");
734*2d1272b8SAndroid Build Coastguard Worker
735*2d1272b8SAndroid Build Coastguard Worker /* Ok, we've got everything we need, now compose output buffer,
736*2d1272b8SAndroid Build Coastguard Worker * very, *very*, carefully! */
737*2d1272b8SAndroid Build Coastguard Worker
738*2d1272b8SAndroid Build Coastguard Worker /* Calculate visual-clusters. That's what we ship. */
739*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < glyphCount; i++)
740*2d1272b8SAndroid Build Coastguard Worker vis_clusters[i] = (uint32_t) -1;
741*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < buffer->len; i++)
742*2d1272b8SAndroid Build Coastguard Worker {
743*2d1272b8SAndroid Build Coastguard Worker uint32_t *p =
744*2d1272b8SAndroid Build Coastguard Worker &vis_clusters[log_clusters[buffer->info[i].utf16_index ()]];
745*2d1272b8SAndroid Build Coastguard Worker *p = hb_min (*p, buffer->info[i].cluster);
746*2d1272b8SAndroid Build Coastguard Worker }
747*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 1; i < glyphCount; i++)
748*2d1272b8SAndroid Build Coastguard Worker if (vis_clusters[i] == (uint32_t) -1)
749*2d1272b8SAndroid Build Coastguard Worker vis_clusters[i] = vis_clusters[i - 1];
750*2d1272b8SAndroid Build Coastguard Worker
751*2d1272b8SAndroid Build Coastguard Worker #undef utf16_index
752*2d1272b8SAndroid Build Coastguard Worker
753*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!buffer->ensure (glyphCount)))
754*2d1272b8SAndroid Build Coastguard Worker FAIL ("Buffer in error");
755*2d1272b8SAndroid Build Coastguard Worker
756*2d1272b8SAndroid Build Coastguard Worker #undef FAIL
757*2d1272b8SAndroid Build Coastguard Worker
758*2d1272b8SAndroid Build Coastguard Worker /* Set glyph infos */
759*2d1272b8SAndroid Build Coastguard Worker buffer->len = 0;
760*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < glyphCount; i++)
761*2d1272b8SAndroid Build Coastguard Worker {
762*2d1272b8SAndroid Build Coastguard Worker hb_glyph_info_t *info = &buffer->info[buffer->len++];
763*2d1272b8SAndroid Build Coastguard Worker
764*2d1272b8SAndroid Build Coastguard Worker info->codepoint = glyphIndices[i];
765*2d1272b8SAndroid Build Coastguard Worker info->cluster = vis_clusters[i];
766*2d1272b8SAndroid Build Coastguard Worker
767*2d1272b8SAndroid Build Coastguard Worker /* The rest is crap. Let's store position info there for now. */
768*2d1272b8SAndroid Build Coastguard Worker info->mask = glyphAdvances[i];
769*2d1272b8SAndroid Build Coastguard Worker info->var1.i32 = glyphOffsets[i].advanceOffset;
770*2d1272b8SAndroid Build Coastguard Worker info->var2.i32 = glyphOffsets[i].ascenderOffset;
771*2d1272b8SAndroid Build Coastguard Worker }
772*2d1272b8SAndroid Build Coastguard Worker
773*2d1272b8SAndroid Build Coastguard Worker /* Set glyph positions */
774*2d1272b8SAndroid Build Coastguard Worker buffer->clear_positions ();
775*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < glyphCount; i++)
776*2d1272b8SAndroid Build Coastguard Worker {
777*2d1272b8SAndroid Build Coastguard Worker hb_glyph_info_t *info = &buffer->info[i];
778*2d1272b8SAndroid Build Coastguard Worker hb_glyph_position_t *pos = &buffer->pos[i];
779*2d1272b8SAndroid Build Coastguard Worker
780*2d1272b8SAndroid Build Coastguard Worker /* TODO vertical */
781*2d1272b8SAndroid Build Coastguard Worker pos->x_advance = x_mult * (int32_t) info->mask;
782*2d1272b8SAndroid Build Coastguard Worker pos->x_offset = x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32);
783*2d1272b8SAndroid Build Coastguard Worker pos->y_offset = y_mult * info->var2.i32;
784*2d1272b8SAndroid Build Coastguard Worker }
785*2d1272b8SAndroid Build Coastguard Worker
786*2d1272b8SAndroid Build Coastguard Worker if (isRightToLeft) hb_buffer_reverse (buffer);
787*2d1272b8SAndroid Build Coastguard Worker
788*2d1272b8SAndroid Build Coastguard Worker buffer->clear_glyph_flags ();
789*2d1272b8SAndroid Build Coastguard Worker buffer->unsafe_to_break ();
790*2d1272b8SAndroid Build Coastguard Worker
791*2d1272b8SAndroid Build Coastguard Worker delete [] clusterMap;
792*2d1272b8SAndroid Build Coastguard Worker delete [] glyphIndices;
793*2d1272b8SAndroid Build Coastguard Worker delete [] textProperties;
794*2d1272b8SAndroid Build Coastguard Worker delete [] glyphProperties;
795*2d1272b8SAndroid Build Coastguard Worker delete [] glyphAdvances;
796*2d1272b8SAndroid Build Coastguard Worker delete [] glyphOffsets;
797*2d1272b8SAndroid Build Coastguard Worker
798*2d1272b8SAndroid Build Coastguard Worker /* Wow, done! */
799*2d1272b8SAndroid Build Coastguard Worker return true;
800*2d1272b8SAndroid Build Coastguard Worker }
801*2d1272b8SAndroid Build Coastguard Worker
802*2d1272b8SAndroid Build Coastguard Worker struct _hb_directwrite_font_table_context {
803*2d1272b8SAndroid Build Coastguard Worker IDWriteFontFace *face;
804*2d1272b8SAndroid Build Coastguard Worker void *table_context;
805*2d1272b8SAndroid Build Coastguard Worker };
806*2d1272b8SAndroid Build Coastguard Worker
807*2d1272b8SAndroid Build Coastguard Worker static void
_hb_directwrite_table_data_release(void * data)808*2d1272b8SAndroid Build Coastguard Worker _hb_directwrite_table_data_release (void *data)
809*2d1272b8SAndroid Build Coastguard Worker {
810*2d1272b8SAndroid Build Coastguard Worker _hb_directwrite_font_table_context *context = (_hb_directwrite_font_table_context *) data;
811*2d1272b8SAndroid Build Coastguard Worker context->face->ReleaseFontTable (context->table_context);
812*2d1272b8SAndroid Build Coastguard Worker hb_free (context);
813*2d1272b8SAndroid Build Coastguard Worker }
814*2d1272b8SAndroid Build Coastguard Worker
815*2d1272b8SAndroid Build Coastguard Worker static hb_blob_t *
_hb_directwrite_reference_table(hb_face_t * face HB_UNUSED,hb_tag_t tag,void * user_data)816*2d1272b8SAndroid Build Coastguard Worker _hb_directwrite_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
817*2d1272b8SAndroid Build Coastguard Worker {
818*2d1272b8SAndroid Build Coastguard Worker IDWriteFontFace *dw_face = ((IDWriteFontFace *) user_data);
819*2d1272b8SAndroid Build Coastguard Worker const void *data;
820*2d1272b8SAndroid Build Coastguard Worker uint32_t length;
821*2d1272b8SAndroid Build Coastguard Worker void *table_context;
822*2d1272b8SAndroid Build Coastguard Worker BOOL exists;
823*2d1272b8SAndroid Build Coastguard Worker if (!dw_face || FAILED (dw_face->TryGetFontTable (hb_uint32_swap (tag), &data,
824*2d1272b8SAndroid Build Coastguard Worker &length, &table_context, &exists)))
825*2d1272b8SAndroid Build Coastguard Worker return nullptr;
826*2d1272b8SAndroid Build Coastguard Worker
827*2d1272b8SAndroid Build Coastguard Worker if (!data || !exists || !length)
828*2d1272b8SAndroid Build Coastguard Worker {
829*2d1272b8SAndroid Build Coastguard Worker dw_face->ReleaseFontTable (table_context);
830*2d1272b8SAndroid Build Coastguard Worker return nullptr;
831*2d1272b8SAndroid Build Coastguard Worker }
832*2d1272b8SAndroid Build Coastguard Worker
833*2d1272b8SAndroid Build Coastguard Worker _hb_directwrite_font_table_context *context = (_hb_directwrite_font_table_context *) hb_malloc (sizeof (_hb_directwrite_font_table_context));
834*2d1272b8SAndroid Build Coastguard Worker context->face = dw_face;
835*2d1272b8SAndroid Build Coastguard Worker context->table_context = table_context;
836*2d1272b8SAndroid Build Coastguard Worker
837*2d1272b8SAndroid Build Coastguard Worker return hb_blob_create ((const char *) data, length, HB_MEMORY_MODE_READONLY,
838*2d1272b8SAndroid Build Coastguard Worker context, _hb_directwrite_table_data_release);
839*2d1272b8SAndroid Build Coastguard Worker }
840*2d1272b8SAndroid Build Coastguard Worker
841*2d1272b8SAndroid Build Coastguard Worker static void
_hb_directwrite_font_release(void * data)842*2d1272b8SAndroid Build Coastguard Worker _hb_directwrite_font_release (void *data)
843*2d1272b8SAndroid Build Coastguard Worker {
844*2d1272b8SAndroid Build Coastguard Worker if (data)
845*2d1272b8SAndroid Build Coastguard Worker ((IDWriteFontFace *) data)->Release ();
846*2d1272b8SAndroid Build Coastguard Worker }
847*2d1272b8SAndroid Build Coastguard Worker
848*2d1272b8SAndroid Build Coastguard Worker /**
849*2d1272b8SAndroid Build Coastguard Worker * hb_directwrite_face_create:
850*2d1272b8SAndroid Build Coastguard Worker * @font_face: a DirectWrite IDWriteFontFace object.
851*2d1272b8SAndroid Build Coastguard Worker *
852*2d1272b8SAndroid Build Coastguard Worker * Constructs a new face object from the specified DirectWrite IDWriteFontFace.
853*2d1272b8SAndroid Build Coastguard Worker *
854*2d1272b8SAndroid Build Coastguard Worker * Return value: #hb_face_t object corresponding to the given input
855*2d1272b8SAndroid Build Coastguard Worker *
856*2d1272b8SAndroid Build Coastguard Worker * Since: 2.4.0
857*2d1272b8SAndroid Build Coastguard Worker **/
858*2d1272b8SAndroid Build Coastguard Worker hb_face_t *
hb_directwrite_face_create(IDWriteFontFace * font_face)859*2d1272b8SAndroid Build Coastguard Worker hb_directwrite_face_create (IDWriteFontFace *font_face)
860*2d1272b8SAndroid Build Coastguard Worker {
861*2d1272b8SAndroid Build Coastguard Worker if (font_face)
862*2d1272b8SAndroid Build Coastguard Worker font_face->AddRef ();
863*2d1272b8SAndroid Build Coastguard Worker return hb_face_create_for_tables (_hb_directwrite_reference_table, font_face,
864*2d1272b8SAndroid Build Coastguard Worker _hb_directwrite_font_release);
865*2d1272b8SAndroid Build Coastguard Worker }
866*2d1272b8SAndroid Build Coastguard Worker
867*2d1272b8SAndroid Build Coastguard Worker /**
868*2d1272b8SAndroid Build Coastguard Worker * hb_directwrite_face_get_font_face:
869*2d1272b8SAndroid Build Coastguard Worker * @face: a #hb_face_t object
870*2d1272b8SAndroid Build Coastguard Worker *
871*2d1272b8SAndroid Build Coastguard Worker * Gets the DirectWrite IDWriteFontFace associated with @face.
872*2d1272b8SAndroid Build Coastguard Worker *
873*2d1272b8SAndroid Build Coastguard Worker * Return value: DirectWrite IDWriteFontFace object corresponding to the given input
874*2d1272b8SAndroid Build Coastguard Worker *
875*2d1272b8SAndroid Build Coastguard Worker * Since: 2.5.0
876*2d1272b8SAndroid Build Coastguard Worker **/
877*2d1272b8SAndroid Build Coastguard Worker IDWriteFontFace *
hb_directwrite_face_get_font_face(hb_face_t * face)878*2d1272b8SAndroid Build Coastguard Worker hb_directwrite_face_get_font_face (hb_face_t *face)
879*2d1272b8SAndroid Build Coastguard Worker {
880*2d1272b8SAndroid Build Coastguard Worker return face->data.directwrite->fontFace;
881*2d1272b8SAndroid Build Coastguard Worker }
882*2d1272b8SAndroid Build Coastguard Worker
883*2d1272b8SAndroid Build Coastguard Worker
884*2d1272b8SAndroid Build Coastguard Worker #endif
885