blob: d63bc04737993a46152ff0ba6ff506bd2578c9e9 [file] [log] [blame]
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +04301/*
Ebrahim Byagowi10c3d9e2016-03-31 18:19:44 +00002 * Copyright © 2015-2016 Ebrahim Byagowi
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +04303 *
4 * This is part of HarfBuzz, a text shaping library.
5 *
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
11 *
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 */
24
25#define HB_SHAPER directwrite
26#include "hb-shaper-impl-private.hh"
27
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +043028#include <DWrite_1.h>
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +043029
30#include "hb-directwrite.h"
31
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +043032
33#ifndef HB_DEBUG_DIRECTWRITE
34#define HB_DEBUG_DIRECTWRITE (HB_DEBUG+0)
35#endif
36
37HB_SHAPER_DATA_ENSURE_DECLARE(directwrite, face)
38HB_SHAPER_DATA_ENSURE_DECLARE(directwrite, font)
39
Ebrahim Byagowi6b861db2016-06-21 13:57:26 +043040
41/*
42 * DirectWrite font stream helpers
43 */
44
45// This is a font loader which provides only one font (unlike its original design).
46// For a better implementation which was also source of this
47// and DWriteFontFileStream, have a look at to NativeFontResourceDWrite.cpp in Mozilla
48class DWriteFontFileLoader : public IDWriteFontFileLoader
49{
50private:
51 IDWriteFontFileStream *mFontFileStream;
52public:
53 DWriteFontFileLoader (IDWriteFontFileStream *fontFileStream) {
54 mFontFileStream = fontFileStream;
55 }
56
57 // IUnknown interface
58 IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) { return S_OK; }
59 IFACEMETHOD_(ULONG, AddRef)() { return 1; }
60 IFACEMETHOD_(ULONG, Release)() { return 1; }
61
62 // IDWriteFontFileLoader methods
63 virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const* fontFileReferenceKey,
64 UINT32 fontFileReferenceKeySize,
65 OUT IDWriteFontFileStream** fontFileStream)
66 {
67 *fontFileStream = mFontFileStream;
68 return S_OK;
69 }
70};
71
72class DWriteFontFileStream : public IDWriteFontFileStream
73{
74private:
75 uint8_t *mData;
76 uint32_t mSize;
77public:
78 DWriteFontFileStream(uint8_t *aData, uint32_t aSize)
79 {
80 mData = aData;
81 mSize = aSize;
82 }
83
84 // IUnknown interface
85 IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) { return S_OK; }
86 IFACEMETHOD_(ULONG, AddRef)() { return 1; }
87 IFACEMETHOD_(ULONG, Release)() { return 1; }
88
89 // IDWriteFontFileStream methods
90 virtual HRESULT STDMETHODCALLTYPE ReadFileFragment(void const** fragmentStart,
91 UINT64 fileOffset,
92 UINT64 fragmentSize,
93 OUT void** fragmentContext)
94 {
95 // We are required to do bounds checking.
96 if (fileOffset + fragmentSize > mSize) {
97 return E_FAIL;
98 }
99
100 // truncate the 64 bit fileOffset to size_t sized index into mData
101 size_t index = static_cast<size_t> (fileOffset);
102
103 // We should be alive for the duration of this.
104 *fragmentStart = &mData[index];
105 *fragmentContext = nullptr;
106 return S_OK;
107 }
108
109 virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext) { }
110
111 virtual HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize)
112 {
113 *fileSize = mSize;
114 return S_OK;
115 }
116
117 virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime)
118 {
119 return E_NOTIMPL;
120 }
121};
122
123
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430124/*
125* shaper face data
126*/
127
128struct hb_directwrite_shaper_face_data_t {
Ebrahim Byagowi07b724f2016-06-24 12:23:25 +0430129 IDWriteFactory *dwriteFactory;
130 IDWriteFontFile *fontFile;
131 IDWriteFontFileStream *fontFileStream;
132 IDWriteFontFileLoader *fontFileLoader;
133 IDWriteFontFace *fontFace;
134 hb_blob_t *faceBlob;
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430135};
136
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430137hb_directwrite_shaper_face_data_t *
138_hb_directwrite_shaper_face_data_create(hb_face_t *face)
139{
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000140 hb_directwrite_shaper_face_data_t *data =
Ebrahim Byagowi6b861db2016-06-21 13:57:26 +0430141 (hb_directwrite_shaper_face_data_t *) malloc (sizeof (hb_directwrite_shaper_face_data_t));
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430142 if (unlikely (!data))
143 return NULL;
144
Ebrahim Byagowi6b861db2016-06-21 13:57:26 +0430145 // TODO: factory and fontFileLoader should be cached separately
146 IDWriteFactory* dwriteFactory;
147 DWriteCreateFactory (
148 DWRITE_FACTORY_TYPE_SHARED,
149 __uuidof (IDWriteFactory),
150 (IUnknown**) &dwriteFactory
151 );
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430152
Ebrahim Byagowi6b861db2016-06-21 13:57:26 +0430153 HRESULT hr;
Ebrahim Byagowibe565d12016-06-24 11:42:01 +0430154 hb_blob_t *blob = hb_face_reference_blob (face);
Ebrahim Byagowi6b861db2016-06-21 13:57:26 +0430155 IDWriteFontFileStream *fontFileStream = new DWriteFontFileStream (
156 (uint8_t*) hb_blob_get_data (blob, NULL), hb_blob_get_length (blob));
157
158 IDWriteFontFileLoader *fontFileLoader = new DWriteFontFileLoader (fontFileStream);
159 dwriteFactory->RegisterFontFileLoader (fontFileLoader);
160
161 IDWriteFontFile *fontFile;
162 uint64_t fontFileKey = 0;
163 hr = dwriteFactory->CreateCustomFontFileReference (&fontFileKey, sizeof (fontFileKey),
164 fontFileLoader, &fontFile);
165
166#define FAIL(...) \
167 HB_STMT_START { \
168 DEBUG_MSG (DIRECTWRITE, NULL, __VA_ARGS__); \
169 return false; \
170 } HB_STMT_END;
171
172 if (FAILED (hr)) {
173 FAIL ("Failed to load font file from data!");
174 return false;
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430175 }
176
Ebrahim Byagowi6b861db2016-06-21 13:57:26 +0430177 BOOL isSupported;
178 DWRITE_FONT_FILE_TYPE fileType;
179 DWRITE_FONT_FACE_TYPE faceType;
180 UINT32 numberOfFaces;
181 hr = fontFile->Analyze (&isSupported, &fileType, &faceType, &numberOfFaces);
182 if (FAILED (hr) || !isSupported) {
183 FAIL ("Font file is not supported.");
184 return false;
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430185 }
186
Ebrahim Byagowi6b861db2016-06-21 13:57:26 +0430187#undef FAIL
188
189 IDWriteFontFace *fontFace;
190 dwriteFactory->CreateFontFace (faceType, 1, &fontFile, 0,
191 DWRITE_FONT_SIMULATIONS_NONE, &fontFace);
192
193 data->dwriteFactory = dwriteFactory;
194 data->fontFile = fontFile;
Ebrahim Byagowi07b724f2016-06-24 12:23:25 +0430195 data->fontFileStream = fontFileStream;
Ebrahim Byagowi6b861db2016-06-21 13:57:26 +0430196 data->fontFileLoader = fontFileLoader;
197 data->fontFace = fontFace;
Ebrahim Byagowibe565d12016-06-24 11:42:01 +0430198 data->faceBlob = blob;
Ebrahim Byagowi6b861db2016-06-21 13:57:26 +0430199
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430200 return data;
201}
202
203void
204_hb_directwrite_shaper_face_data_destroy(hb_directwrite_shaper_face_data_t *data)
205{
Ebrahim Byagowi07b724f2016-06-24 12:23:25 +0430206 if (data->fontFace)
207 data->fontFace->Release ();
208 if (data->fontFile)
209 data->fontFile->Release ();
210 if (data->dwriteFactory) {
211 if (data->fontFileLoader)
ebraminio1e1825b2016-12-17 10:30:40 +0330212 data->dwriteFactory->UnregisterFontFileLoader (data->fontFileLoader);
213 data->dwriteFactory->Release ();
Ebrahim Byagowi07b724f2016-06-24 12:23:25 +0430214 }
215 if (data->fontFileLoader)
216 delete data->fontFileLoader;
217 if (data->fontFileStream)
218 delete data->fontFileStream;
219 if (data->faceBlob)
220 hb_blob_destroy (data->faceBlob);
221 if (data)
222 free (data);
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430223}
224
225
226/*
227 * shaper font data
228 */
229
230struct hb_directwrite_shaper_font_data_t {
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430231};
232
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430233hb_directwrite_shaper_font_data_t *
234_hb_directwrite_shaper_font_data_create (hb_font_t *font)
235{
236 if (unlikely (!hb_directwrite_shaper_face_data_ensure (font->face))) return NULL;
237
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000238 hb_directwrite_shaper_font_data_t *data =
Ebrahim Byagowi6b861db2016-06-21 13:57:26 +0430239 (hb_directwrite_shaper_font_data_t *) malloc (sizeof (hb_directwrite_shaper_font_data_t));
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430240 if (unlikely (!data))
241 return NULL;
242
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430243 return data;
244}
245
246void
247_hb_directwrite_shaper_font_data_destroy (hb_directwrite_shaper_font_data_t *data)
248{
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430249 free (data);
250}
251
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430252
253/*
254 * shaper shape_plan data
255 */
256
257struct hb_directwrite_shaper_shape_plan_data_t {};
258
259hb_directwrite_shaper_shape_plan_data_t *
260_hb_directwrite_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
Behdad Esfahbod72ada4f2016-09-10 03:57:24 -0700261 const hb_feature_t *user_features HB_UNUSED,
262 unsigned int num_user_features HB_UNUSED,
263 const int *coords HB_UNUSED,
264 unsigned int num_coords HB_UNUSED)
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430265{
266 return (hb_directwrite_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
267}
268
269void
270_hb_directwrite_shaper_shape_plan_data_destroy (hb_directwrite_shaper_shape_plan_data_t *data HB_UNUSED)
271{
272}
273
Ebrahim Byagowi6b861db2016-06-21 13:57:26 +0430274// Most of TextAnalysis is originally written by Bas Schouten for Mozilla project
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430275// but now is relicensed to MIT for HarfBuzz use
276class TextAnalysis
277 : public IDWriteTextAnalysisSource, public IDWriteTextAnalysisSink
278{
279public:
280
281 IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) { return S_OK; }
282 IFACEMETHOD_(ULONG, AddRef)() { return 1; }
283 IFACEMETHOD_(ULONG, Release)() { return 1; }
284
285 // A single contiguous run of characters containing the same analysis
286 // results.
287 struct Run
288 {
Ebrahim Byagowi63ee9ca2016-04-01 15:47:07 +0000289 uint32_t mTextStart; // starting text position of this run
290 uint32_t mTextLength; // number of contiguous code units covered
291 uint32_t mGlyphStart; // starting glyph in the glyphs array
292 uint32_t mGlyphCount; // number of glyphs associated with this run of
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430293 // text
294 DWRITE_SCRIPT_ANALYSIS mScript;
Ebrahim Byagowi63ee9ca2016-04-01 15:47:07 +0000295 uint8_t mBidiLevel;
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430296 bool mIsSideways;
297
Ebrahim Byagowi63ee9ca2016-04-01 15:47:07 +0000298 inline bool ContainsTextPosition(uint32_t aTextPosition) const
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430299 {
300 return aTextPosition >= mTextStart
301 && aTextPosition < mTextStart + mTextLength;
302 }
303
304 Run *nextRun;
305 };
306
307public:
308 TextAnalysis(const wchar_t* text,
Ebrahim Byagowi63ee9ca2016-04-01 15:47:07 +0000309 uint32_t textLength,
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430310 const wchar_t* localeName,
311 DWRITE_READING_DIRECTION readingDirection)
312 : mText(text)
313 , mTextLength(textLength)
314 , mLocaleName(localeName)
315 , mReadingDirection(readingDirection)
316 , mCurrentRun(NULL) { };
317
318 ~TextAnalysis() {
319 // delete runs, except mRunHead which is part of the TextAnalysis object
320 for (Run *run = mRunHead.nextRun; run;) {
321 Run *origRun = run;
322 run = run->nextRun;
Ebrahim Byagowi10c3d9e2016-03-31 18:19:44 +0000323 free (origRun);
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430324 }
325 }
326
327 STDMETHODIMP GenerateResults(IDWriteTextAnalyzer* textAnalyzer,
328 Run **runHead) {
329 // Analyzes the text using the script analyzer and returns
330 // the result as a series of runs.
331
332 HRESULT hr = S_OK;
333
334 // Initially start out with one result that covers the entire range.
335 // This result will be subdivided by the analysis processes.
336 mRunHead.mTextStart = 0;
337 mRunHead.mTextLength = mTextLength;
338 mRunHead.mBidiLevel =
339 (mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
340 mRunHead.nextRun = NULL;
341 mCurrentRun = &mRunHead;
342
343 // Call each of the analyzers in sequence, recording their results.
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000344 if (SUCCEEDED (hr = textAnalyzer->AnalyzeScript (this, 0, mTextLength, this))) {
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430345 *runHead = &mRunHead;
346 }
347
348 return hr;
349 }
350
351 // IDWriteTextAnalysisSource implementation
352
Ebrahim Byagowi63ee9ca2016-04-01 15:47:07 +0000353 IFACEMETHODIMP GetTextAtPosition(uint32_t textPosition,
354 OUT wchar_t const** textString,
355 OUT uint32_t* textLength)
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430356 {
357 if (textPosition >= mTextLength) {
358 // No text at this position, valid query though.
359 *textString = NULL;
360 *textLength = 0;
361 }
362 else {
363 *textString = mText + textPosition;
364 *textLength = mTextLength - textPosition;
365 }
366 return S_OK;
367 }
368
Ebrahim Byagowi63ee9ca2016-04-01 15:47:07 +0000369 IFACEMETHODIMP GetTextBeforePosition(uint32_t textPosition,
370 OUT wchar_t const** textString,
371 OUT uint32_t* textLength)
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430372 {
373 if (textPosition == 0 || textPosition > mTextLength) {
374 // Either there is no text before here (== 0), or this
375 // is an invalid position. The query is considered valid thouh.
376 *textString = NULL;
377 *textLength = 0;
378 }
379 else {
380 *textString = mText;
381 *textLength = textPosition;
382 }
383 return S_OK;
384 }
385
386 IFACEMETHODIMP_(DWRITE_READING_DIRECTION)
387 GetParagraphReadingDirection() { return mReadingDirection; }
388
Ebrahim Byagowi63ee9ca2016-04-01 15:47:07 +0000389 IFACEMETHODIMP GetLocaleName(uint32_t textPosition,
390 uint32_t* textLength,
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430391 wchar_t const** localeName)
392 {
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430393 return S_OK;
394 }
395
396 IFACEMETHODIMP
Ebrahim Byagowi63ee9ca2016-04-01 15:47:07 +0000397 GetNumberSubstitution(uint32_t textPosition,
398 OUT uint32_t* textLength,
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430399 OUT IDWriteNumberSubstitution** numberSubstitution)
400 {
401 // We do not support number substitution.
402 *numberSubstitution = NULL;
403 *textLength = mTextLength - textPosition;
404
405 return S_OK;
406 }
407
408 // IDWriteTextAnalysisSink implementation
409
410 IFACEMETHODIMP
Ebrahim Byagowi63ee9ca2016-04-01 15:47:07 +0000411 SetScriptAnalysis(uint32_t textPosition,
412 uint32_t textLength,
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430413 DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis)
414 {
415 SetCurrentRun(textPosition);
416 SplitCurrentRun(textPosition);
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430417 while (textLength > 0)
418 {
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430419 Run *run = FetchNextRun(&textLength);
420 run->mScript = *scriptAnalysis;
421 }
422
423 return S_OK;
424 }
425
426 IFACEMETHODIMP
Ebrahim Byagowi63ee9ca2016-04-01 15:47:07 +0000427 SetLineBreakpoints(uint32_t textPosition,
428 uint32_t textLength,
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430429 const DWRITE_LINE_BREAKPOINT* lineBreakpoints) { return S_OK; }
430
Ebrahim Byagowi63ee9ca2016-04-01 15:47:07 +0000431 IFACEMETHODIMP SetBidiLevel(uint32_t textPosition,
432 uint32_t textLength,
433 uint8_t explicitLevel,
434 uint8_t resolvedLevel) { return S_OK; }
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430435
436 IFACEMETHODIMP
Ebrahim Byagowi63ee9ca2016-04-01 15:47:07 +0000437 SetNumberSubstitution(uint32_t textPosition,
438 uint32_t textLength,
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430439 IDWriteNumberSubstitution* numberSubstitution) { return S_OK; }
440
441protected:
Ebrahim Byagowi63ee9ca2016-04-01 15:47:07 +0000442 Run *FetchNextRun(IN OUT uint32_t* textLength)
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430443 {
444 // Used by the sink setters, this returns a reference to the next run.
445 // Position and length are adjusted to now point after the current run
446 // being returned.
447
448 Run *origRun = mCurrentRun;
449 // Split the tail if needed (the length remaining is less than the
450 // current run's size).
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430451 if (*textLength < mCurrentRun->mTextLength)
452 {
453 SplitCurrentRun (mCurrentRun->mTextStart + *textLength);
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430454 }
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430455 else
456 {
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430457 // Just advance the current run.
458 mCurrentRun = mCurrentRun->nextRun;
459 }
460 *textLength -= origRun->mTextLength;
461
462 // Return a reference to the run that was just current.
463 return origRun;
464 }
465
Ebrahim Byagowi63ee9ca2016-04-01 15:47:07 +0000466 void SetCurrentRun(uint32_t textPosition)
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430467 {
468 // Move the current run to the given position.
469 // Since the analyzers generally return results in a forward manner,
470 // this will usually just return early. If not, find the
471 // corresponding run for the text position.
472
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430473 if (mCurrentRun && mCurrentRun->ContainsTextPosition (textPosition))
474 {
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430475 return;
476 }
477
478 for (Run *run = &mRunHead; run; run = run->nextRun) {
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430479 if (run->ContainsTextPosition (textPosition))
480 {
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430481 mCurrentRun = run;
482 return;
483 }
484 }
485 //NS_NOTREACHED("We should always be able to find the text position in one \
486 // of our runs");
487 }
488
Ebrahim Byagowi63ee9ca2016-04-01 15:47:07 +0000489 void SplitCurrentRun(uint32_t splitPosition)
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430490 {
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430491 if (!mCurrentRun)
492 {
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430493 //NS_ASSERTION(false, "SplitCurrentRun called without current run.");
494 // Shouldn't be calling this when no current run is set!
495 return;
496 }
497 // Split the current run.
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430498 if (splitPosition <= mCurrentRun->mTextStart)
499 {
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430500 // No need to split, already the start of a run
501 // or before it. Usually the first.
502 return;
503 }
Ebrahim Byagowi10c3d9e2016-03-31 18:19:44 +0000504 Run *newRun = (Run*) malloc (sizeof (Run));
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430505
506 *newRun = *mCurrentRun;
507
508 // Insert the new run in our linked list.
509 newRun->nextRun = mCurrentRun->nextRun;
510 mCurrentRun->nextRun = newRun;
511
512 // Adjust runs' text positions and lengths.
Ebrahim Byagowi63ee9ca2016-04-01 15:47:07 +0000513 uint32_t splitPoint = splitPosition - mCurrentRun->mTextStart;
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430514 newRun->mTextStart += splitPoint;
515 newRun->mTextLength -= splitPoint;
516 mCurrentRun->mTextLength = splitPoint;
517 mCurrentRun = newRun;
518 }
519
520protected:
521 // Input
522 // (weak references are fine here, since this class is a transient
523 // stack-based helper that doesn't need to copy data)
Ebrahim Byagowi63ee9ca2016-04-01 15:47:07 +0000524 uint32_t mTextLength;
525 const wchar_t* mText;
526 const wchar_t* mLocaleName;
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430527 DWRITE_READING_DIRECTION mReadingDirection;
528
529 // Current processing state.
530 Run *mCurrentRun;
531
532 // Output is a list of runs starting here
533 Run mRunHead;
534};
535
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430536static inline uint16_t hb_uint16_swap (const uint16_t v)
Ebrahim Byagowi10c3d9e2016-03-31 18:19:44 +0000537{ return (v >> 8) | (v << 8); }
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430538static inline uint32_t hb_uint32_swap (const uint32_t v)
Ebrahim Byagowi10c3d9e2016-03-31 18:19:44 +0000539{ return (hb_uint16_swap(v) << 16) | hb_uint16_swap(v >> 16); }
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430540
541/*
542 * shaper
543 */
544
ebraminio1e1825b2016-12-17 10:30:40 +0330545static hb_bool_t
546_hb_directwrite_shape_full(hb_shape_plan_t *shape_plan,
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430547 hb_font_t *font,
548 hb_buffer_t *buffer,
549 const hb_feature_t *features,
ebraminio1e1825b2016-12-17 10:30:40 +0330550 unsigned int num_features,
551 float lineWidth)
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430552{
553 hb_face_t *face = font->face;
554 hb_directwrite_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
555 hb_directwrite_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
Ebrahim Byagowi6b861db2016-06-21 13:57:26 +0430556 IDWriteFactory *dwriteFactory = face_data->dwriteFactory;
557 IDWriteFontFace *fontFace = face_data->fontFace;
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430558
559 IDWriteTextAnalyzer* analyzer;
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000560 dwriteFactory->CreateTextAnalyzer(&analyzer);
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430561
562 unsigned int scratch_size;
563 hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
564#define ALLOCATE_ARRAY(Type, name, len) \
565 Type *name = (Type *) scratch; \
566 { \
567 unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
568 assert (_consumed <= scratch_size); \
569 scratch += _consumed; \
570 scratch_size -= _consumed; \
571 }
572
573#define utf16_index() var1.u32
574
Ebrahim Byagowi63ee9ca2016-04-01 15:47:07 +0000575 ALLOCATE_ARRAY(wchar_t, textString, buffer->len * 2);
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430576
577 unsigned int chars_len = 0;
578 for (unsigned int i = 0; i < buffer->len; i++)
579 {
580 hb_codepoint_t c = buffer->info[i].codepoint;
581 buffer->info[i].utf16_index() = chars_len;
582 if (likely(c <= 0xFFFFu))
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000583 textString[chars_len++] = c;
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430584 else if (unlikely(c > 0x10FFFFu))
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000585 textString[chars_len++] = 0xFFFDu;
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430586 else {
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000587 textString[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
Behdad Esfahbod33317312016-08-08 17:24:04 -0700588 textString[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1u << 10) - 1));
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430589 }
590 }
591
592 ALLOCATE_ARRAY(WORD, log_clusters, chars_len);
Ebrahim Byagowid3134a62016-04-05 21:01:05 +0000593 // if (num_features)
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430594 {
595 /* Need log_clusters to assign features. */
596 chars_len = 0;
597 for (unsigned int i = 0; i < buffer->len; i++)
598 {
599 hb_codepoint_t c = buffer->info[i].codepoint;
600 unsigned int cluster = buffer->info[i].cluster;
601 log_clusters[chars_len++] = cluster;
602 if (hb_in_range(c, 0x10000u, 0x10FFFFu))
603 log_clusters[chars_len++] = cluster; /* Surrogates. */
604 }
605 }
606
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430607 // TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES
608
609 DWRITE_READING_DIRECTION readingDirection = buffer->props.direction ?
610 DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
611 DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
612
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +0400613 /*
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430614 * There's an internal 16-bit limit on some things inside the analyzer,
615 * but we never attempt to shape a word longer than 64K characters
616 * in a single gfxShapedWord, so we cannot exceed that limit.
617 */
Ebrahim Byagowi63ee9ca2016-04-01 15:47:07 +0000618 uint32_t textLength = buffer->len;
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430619
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000620 TextAnalysis analysis(textString, textLength, NULL, readingDirection);
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430621 TextAnalysis::Run *runHead;
Ebrahim Byagowi6b861db2016-06-21 13:57:26 +0430622 HRESULT hr;
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430623 hr = analysis.GenerateResults(analyzer, &runHead);
624
Ebrahim Byagowi10c3d9e2016-03-31 18:19:44 +0000625#define FAIL(...) \
626 HB_STMT_START { \
627 DEBUG_MSG (DIRECTWRITE, NULL, __VA_ARGS__); \
628 return false; \
629 } HB_STMT_END;
630
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000631 if (FAILED (hr))
632 {
Ebrahim Byagowi10c3d9e2016-03-31 18:19:44 +0000633 FAIL ("Analyzer failed to generate results.");
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430634 return false;
635 }
636
Ebrahim Byagowi63ee9ca2016-04-01 15:47:07 +0000637 uint32_t maxGlyphCount = 3 * textLength / 2 + 16;
638 uint32_t glyphCount;
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000639 bool isRightToLeft = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430640
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000641 const wchar_t localeName[20] = {0};
642 if (buffer->props.language != NULL)
643 {
644 mbstowcs ((wchar_t*) localeName,
645 hb_language_to_string (buffer->props.language), 20);
Ebrahim Byagowid691ba32016-03-30 20:21:40 +0000646 }
647
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000648 DWRITE_TYPOGRAPHIC_FEATURES singleFeatures;
649 singleFeatures.featureCount = num_features;
Ebrahim Byagowid3134a62016-04-05 21:01:05 +0000650 if (num_features)
Ebrahim Byagowi10c3d9e2016-03-31 18:19:44 +0000651 {
652 DWRITE_FONT_FEATURE* dwfeatureArray = (DWRITE_FONT_FEATURE*)
653 malloc (sizeof (DWRITE_FONT_FEATURE) * num_features);
654 for (unsigned int i = 0; i < num_features; ++i)
655 {
656 dwfeatureArray[i].nameTag = (DWRITE_FONT_FEATURE_TAG)
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000657 hb_uint32_swap (features[i].tag);
Ebrahim Byagowi10c3d9e2016-03-31 18:19:44 +0000658 dwfeatureArray[i].parameter = features[i].value;
659 }
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000660 singleFeatures.features = dwfeatureArray;
Ebrahim Byagowi10c3d9e2016-03-31 18:19:44 +0000661 }
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000662 const DWRITE_TYPOGRAPHIC_FEATURES* dwFeatures =
663 (const DWRITE_TYPOGRAPHIC_FEATURES*) &singleFeatures;
Ebrahim Byagowi63ee9ca2016-04-01 15:47:07 +0000664 const uint32_t featureRangeLengths[] = { textLength };
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430665
Ebrahim Byagowi8179ff52016-06-27 03:54:15 +0430666 uint16_t* clusterMap = (uint16_t*) malloc (textLength * sizeof (uint16_t));
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000667 DWRITE_SHAPING_TEXT_PROPERTIES* textProperties = (DWRITE_SHAPING_TEXT_PROPERTIES*)
Ebrahim Byagowi8179ff52016-06-27 03:54:15 +0430668 malloc (textLength * sizeof (DWRITE_SHAPING_TEXT_PROPERTIES));
669retry_getglyphs:
670 uint16_t* glyphIndices = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000671 DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*)
672 malloc (maxGlyphCount * sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES));
673
Behdad Esfahbod5dfd3412017-01-22 16:55:40 -0800674 hr = analyzer->GetGlyphs (textString, textLength, fontFace, false,
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000675 isRightToLeft, &runHead->mScript, localeName, NULL, &dwFeatures,
676 featureRangeLengths, 1, maxGlyphCount, clusterMap, textProperties, glyphIndices,
677 glyphProperties, &glyphCount);
678
679 if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)))
680 {
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000681 free (glyphIndices);
Ebrahim Byagowid1298972016-03-31 13:45:37 +0000682 free (glyphProperties);
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430683
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000684 maxGlyphCount *= 2;
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430685
Ebrahim Byagowid1298972016-03-31 13:45:37 +0000686 goto retry_getglyphs;
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430687 }
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000688 if (FAILED (hr))
689 {
Ebrahim Byagowid1298972016-03-31 13:45:37 +0000690 FAIL ("Analyzer failed to get glyphs.");
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430691 return false;
692 }
693
Ebrahim Byagowi63ee9ca2016-04-01 15:47:07 +0000694 float* glyphAdvances = (float*) malloc (maxGlyphCount * sizeof (float));
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000695 DWRITE_GLYPH_OFFSET* glyphOffsets = (DWRITE_GLYPH_OFFSET*)
696 malloc(maxGlyphCount * sizeof (DWRITE_GLYPH_OFFSET));
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430697
698 /* The -2 in the following is to compensate for possible
699 * alignment needed after the WORD array. sizeof(WORD) == 2. */
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000700 unsigned int glyphs_size = (scratch_size * sizeof(int) - 2)
701 / (sizeof(WORD) +
702 sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES) +
703 sizeof(int) +
704 sizeof(DWRITE_GLYPH_OFFSET) +
705 sizeof(uint32_t));
706 ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430707
708#undef ALLOCATE_ARRAY
709
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000710 int fontEmSize = font->face->get_upem();
711 if (fontEmSize < 0)
712 fontEmSize = -fontEmSize;
Ebrahim Byagowi5f1a8962016-03-31 12:26:16 +0000713
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000714 if (fontEmSize < 0)
715 fontEmSize = -fontEmSize;
716 double x_mult = (double) font->x_scale / fontEmSize;
717 double y_mult = (double) font->y_scale / fontEmSize;
Ebrahim Byagowi1c00a462016-03-30 20:15:09 +0000718
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000719 hr = analyzer->GetGlyphPlacements (textString,
720 clusterMap, textProperties, textLength, glyphIndices,
721 glyphProperties, glyphCount, fontFace, fontEmSize,
Behdad Esfahbod5dfd3412017-01-22 16:55:40 -0800722 false, isRightToLeft, &runHead->mScript, localeName,
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000723 &dwFeatures, featureRangeLengths, 1,
724 glyphAdvances, glyphOffsets);
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430725
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000726 if (FAILED (hr))
727 {
Ebrahim Byagowid1298972016-03-31 13:45:37 +0000728 FAIL ("Analyzer failed to get glyph placements.");
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430729 return false;
730 }
731
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430732 IDWriteTextAnalyzer1* analyzer1;
733 analyzer->QueryInterface (&analyzer1);
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000734
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430735 if (analyzer1 && lineWidth)
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000736 {
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000737
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430738 DWRITE_JUSTIFICATION_OPPORTUNITY* justificationOpportunities =
739 (DWRITE_JUSTIFICATION_OPPORTUNITY*)
740 malloc (maxGlyphCount * sizeof (DWRITE_JUSTIFICATION_OPPORTUNITY));
741 hr = analyzer1->GetJustificationOpportunities (fontFace, fontEmSize,
742 runHead->mScript, textLength, glyphCount, textString, clusterMap,
743 glyphProperties, justificationOpportunities);
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000744
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430745 if (FAILED (hr))
746 {
747 FAIL ("Analyzer failed to get justification opportunities.");
748 return false;
749 }
750
751 float* justifiedGlyphAdvances =
752 (float*) malloc (maxGlyphCount * sizeof (float));
753 DWRITE_GLYPH_OFFSET* justifiedGlyphOffsets = (DWRITE_GLYPH_OFFSET*)
754 malloc (glyphCount * sizeof (DWRITE_GLYPH_OFFSET));
755 hr = analyzer1->JustifyGlyphAdvances (lineWidth, glyphCount, justificationOpportunities,
756 glyphAdvances, glyphOffsets, justifiedGlyphAdvances, justifiedGlyphOffsets);
757
758 if (FAILED (hr))
759 {
760 FAIL("Analyzer failed to get justified glyph advances.");
761 return false;
762 }
763
764 DWRITE_SCRIPT_PROPERTIES scriptProperties;
765 hr = analyzer1->GetScriptProperties (runHead->mScript, &scriptProperties);
766 if (FAILED (hr))
767 {
768 FAIL("Analyzer failed to get script properties.");
769 return false;
770 }
771 uint32_t justificationCharacter = scriptProperties.justificationCharacter;
772
773 // if a script justificationCharacter is not space, it can have GetJustifiedGlyphs
774 if (justificationCharacter != 32)
775 {
Ebrahim Byagowi8179ff52016-06-27 03:54:15 +0430776 uint16_t* modifiedClusterMap = (uint16_t*) malloc (textLength * sizeof (uint16_t));
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430777 retry_getjustifiedglyphs:
Ebrahim Byagowi8179ff52016-06-27 03:54:15 +0430778 uint16_t* modifiedGlyphIndices = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
779 float* modifiedGlyphAdvances = (float*) malloc (maxGlyphCount * sizeof (float));
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430780 DWRITE_GLYPH_OFFSET* modifiedGlyphOffsets = (DWRITE_GLYPH_OFFSET*)
781 malloc (maxGlyphCount * sizeof (DWRITE_GLYPH_OFFSET));
782 uint32_t actualGlyphsCount;
783 hr = analyzer1->GetJustifiedGlyphs (fontFace, fontEmSize, runHead->mScript,
Ebrahim Byagowiadf20ba2016-04-01 15:36:40 +0000784 textLength, glyphCount, maxGlyphCount, clusterMap, glyphIndices,
785 glyphAdvances, justifiedGlyphAdvances, justifiedGlyphOffsets,
786 glyphProperties, &actualGlyphsCount, modifiedClusterMap, modifiedGlyphIndices,
787 modifiedGlyphAdvances, modifiedGlyphOffsets);
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000788
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430789 if (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER))
790 {
791 maxGlyphCount = actualGlyphsCount;
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430792 free (modifiedGlyphIndices);
793 free (modifiedGlyphAdvances);
794 free (modifiedGlyphOffsets);
Ebrahim Byagowiadf20ba2016-04-01 15:36:40 +0000795
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430796 maxGlyphCount = actualGlyphsCount;
Ebrahim Byagowiadf20ba2016-04-01 15:36:40 +0000797
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430798 goto retry_getjustifiedglyphs;
799 }
800 if (FAILED (hr))
801 {
802 FAIL ("Analyzer failed to get justified glyphs.");
803 return false;
804 }
805
806 free (clusterMap);
807 free (glyphIndices);
808 free (glyphAdvances);
809 free (glyphOffsets);
810
811 glyphCount = actualGlyphsCount;
812 clusterMap = modifiedClusterMap;
813 glyphIndices = modifiedGlyphIndices;
814 glyphAdvances = modifiedGlyphAdvances;
815 glyphOffsets = modifiedGlyphOffsets;
816
817 free (justifiedGlyphAdvances);
818 free (justifiedGlyphOffsets);
Ebrahim Byagowiadf20ba2016-04-01 15:36:40 +0000819 }
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430820 else
Ebrahim Byagowiadf20ba2016-04-01 15:36:40 +0000821 {
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430822 free (glyphAdvances);
823 free (glyphOffsets);
824
825 glyphAdvances = justifiedGlyphAdvances;
826 glyphOffsets = justifiedGlyphOffsets;
Ebrahim Byagowiadf20ba2016-04-01 15:36:40 +0000827 }
828
Ebrahim Byagowif3f0ea92016-06-23 16:41:37 +0430829 free (justificationOpportunities);
Ebrahim Byagowiadf20ba2016-04-01 15:36:40 +0000830
Ebrahim Byagowiadf20ba2016-04-01 15:36:40 +0000831 }
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000832
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430833 /* Ok, we've got everything we need, now compose output buffer,
834 * very, *very*, carefully! */
835
836 /* Calculate visual-clusters. That's what we ship. */
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000837 for (unsigned int i = 0; i < glyphCount; i++)
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430838 vis_clusters[i] = -1;
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000839 for (unsigned int i = 0; i < buffer->len; i++)
840 {
841 uint32_t *p =
842 &vis_clusters[log_clusters[buffer->info[i].utf16_index()]];
Ebrahim Byagowi10c3d9e2016-03-31 18:19:44 +0000843 *p = MIN (*p, buffer->info[i].cluster);
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430844 }
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000845 for (unsigned int i = 1; i < glyphCount; i++)
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430846 if (vis_clusters[i] == -1)
847 vis_clusters[i] = vis_clusters[i - 1];
848
849#undef utf16_index
850
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000851 if (unlikely (!buffer->ensure (glyphCount)))
Ebrahim Byagowid1298972016-03-31 13:45:37 +0000852 FAIL ("Buffer in error");
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430853
854#undef FAIL
855
856 /* Set glyph infos */
857 buffer->len = 0;
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000858 for (unsigned int i = 0; i < glyphCount; i++)
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430859 {
860 hb_glyph_info_t *info = &buffer->info[buffer->len++];
861
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000862 info->codepoint = glyphIndices[i];
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430863 info->cluster = vis_clusters[i];
864
865 /* The rest is crap. Let's store position info there for now. */
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000866 info->mask = glyphAdvances[i];
867 info->var1.i32 = glyphOffsets[i].advanceOffset;
868 info->var2.i32 = glyphOffsets[i].ascenderOffset;
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430869 }
870
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430871 /* Set glyph positions */
872 buffer->clear_positions ();
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000873 for (unsigned int i = 0; i < glyphCount; i++)
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430874 {
875 hb_glyph_info_t *info = &buffer->info[i];
876 hb_glyph_position_t *pos = &buffer->pos[i];
877
878 /* TODO vertical */
Ebrahim Byagowi5f1a8962016-03-31 12:26:16 +0000879 pos->x_advance = x_mult * (int32_t) info->mask;
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000880 pos->x_offset =
881 x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32);
Ebrahim Byagowi5f1a8962016-03-31 12:26:16 +0000882 pos->y_offset = y_mult * info->var2.i32;
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430883 }
884
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000885 if (isRightToLeft)
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430886 hb_buffer_reverse (buffer);
887
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000888 free (clusterMap);
889 free (glyphIndices);
Ebrahim Byagowid1298972016-03-31 13:45:37 +0000890 free (textProperties);
891 free (glyphProperties);
Ebrahim Byagowi32ae9d12016-04-01 06:39:57 +0000892 free (glyphAdvances);
893 free (glyphOffsets);
Ebrahim Byagowid3134a62016-04-05 21:01:05 +0000894
895 if (num_features)
896 free (singleFeatures.features);
Ebrahim Byagowi5f1a8962016-03-31 12:26:16 +0000897
Ebrahim Byagowif35b3e92015-09-11 09:48:12 +0430898 /* Wow, done! */
899 return true;
Khaled Hosnyd7bf9d02015-12-29 02:23:24 +0400900}
ebraminio1e1825b2016-12-17 10:30:40 +0330901
902hb_bool_t
903_hb_directwrite_shape(hb_shape_plan_t *shape_plan,
904 hb_font_t *font,
905 hb_buffer_t *buffer,
906 const hb_feature_t *features,
907 unsigned int num_features)
908{
909 return _hb_directwrite_shape_full(shape_plan, font, buffer,
910 features, num_features, 0);
911}
912
913/*
914 * Public [experimental] API
915 */
916
917hb_bool_t
Behdad Esfahbodd2f249e2017-01-22 17:42:33 -0800918hb_directwrite_shape_experimental_width(hb_font_t *font,
ebraminio1e1825b2016-12-17 10:30:40 +0330919 hb_buffer_t *buffer,
920 const hb_feature_t *features,
921 unsigned int num_features,
922 float width)
923{
924 static char *shapers = "directwrite";
925 hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face,
926 &buffer->props, features, num_features, &shapers);
927 hb_bool_t res = _hb_directwrite_shape_full (shape_plan, font, buffer,
928 features, num_features, width);
929
930 if (res)
931 buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
932
933 return res;
934}