| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright © 2015 Ebrahim Byagowi | 2 * Copyright © 2015-2016 Ebrahim Byagowi |
| 3 * | 3 * |
| 4 * This is part of HarfBuzz, a text shaping library. | 4 * This is part of HarfBuzz, a text shaping library. |
| 5 * | 5 * |
| 6 * Permission is hereby granted, without written agreement and without | 6 * Permission is hereby granted, without written agreement and without |
| 7 * license or royalty fees, to use, copy, modify, and distribute this | 7 * license or royalty fees, to use, copy, modify, and distribute this |
| 8 * software and its documentation for any purpose, provided that the | 8 * software and its documentation for any purpose, provided that the |
| 9 * above copyright notice and the following two paragraphs appear in | 9 * above copyright notice and the following two paragraphs appear in |
| 10 * all copies of this software. | 10 * all copies of this software. |
| 11 * | 11 * |
| 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR | 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
| 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES | 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
| 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN | 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 | 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
| 16 * DAMAGE. | 16 * DAMAGE. |
| 17 * | 17 * |
| 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, | 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
| 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
| 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS | 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 | 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
| 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
| 23 */ | 23 */ |
| 24 | 24 |
| 25 #define HB_SHAPER directwrite | 25 #define HB_SHAPER directwrite |
| 26 #include "hb-shaper-impl-private.hh" | 26 #include "hb-shaper-impl-private.hh" |
| 27 | 27 |
| 28 #include <dwrite.h> | 28 #ifndef HB_DIRECTWRITE_EXPERIMENTAL_JUSTIFICATION |
| 29 #include <DWrite.h> |
| 30 #else |
| 31 #include <DWrite_1.h> |
| 32 #endif |
| 29 | 33 |
| 30 #include "hb-directwrite.h" | 34 #include "hb-directwrite.h" |
| 31 | 35 |
| 32 #include "hb-open-file-private.hh" | 36 #include "hb-open-file-private.hh" |
| 33 #include "hb-ot-name-table.hh" | 37 #include "hb-ot-name-table.hh" |
| 34 #include "hb-ot-tag.h" | 38 #include "hb-ot-tag.h" |
| 35 | 39 |
| 36 | 40 |
| 37 #ifndef HB_DEBUG_DIRECTWRITE | 41 #ifndef HB_DEBUG_DIRECTWRITE |
| 38 #define HB_DEBUG_DIRECTWRITE (HB_DEBUG+0) | 42 #define HB_DEBUG_DIRECTWRITE (HB_DEBUG+0) |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 * bother. */ | 173 * bother. */ |
| 170 | 174 |
| 171 hb_blob_destroy (blob); | 175 hb_blob_destroy (blob); |
| 172 return hb_blob_create ((const char *)new_sfnt_data, new_length, | 176 return hb_blob_create ((const char *)new_sfnt_data, new_length, |
| 173 HB_MEMORY_MODE_WRITABLE, NULL, free); | 177 HB_MEMORY_MODE_WRITABLE, NULL, free); |
| 174 } | 178 } |
| 175 | 179 |
| 176 hb_directwrite_shaper_face_data_t * | 180 hb_directwrite_shaper_face_data_t * |
| 177 _hb_directwrite_shaper_face_data_create(hb_face_t *face) | 181 _hb_directwrite_shaper_face_data_create(hb_face_t *face) |
| 178 { | 182 { |
| 179 hb_directwrite_shaper_face_data_t *data = (hb_directwrite_shaper_face_data_t *
)calloc(1, sizeof (hb_directwrite_shaper_face_data_t)); | 183 hb_directwrite_shaper_face_data_t *data = |
| 184 (hb_directwrite_shaper_face_data_t *) calloc (1, sizeof (hb_directwrite_shap
er_face_data_t)); |
| 180 if (unlikely (!data)) | 185 if (unlikely (!data)) |
| 181 return NULL; | 186 return NULL; |
| 182 | 187 |
| 183 hb_blob_t *blob = hb_face_reference_blob (face); | 188 hb_blob_t *blob = hb_face_reference_blob (face); |
| 184 if (unlikely (!hb_blob_get_length (blob))) | 189 if (unlikely (!hb_blob_get_length (blob))) |
| 185 DEBUG_MSG(DIRECTWRITE, face, "Face has empty blob"); | 190 DEBUG_MSG(DIRECTWRITE, face, "Face has empty blob"); |
| 186 | 191 |
| 187 blob = _hb_rename_font (blob, data->face_name); | 192 blob = _hb_rename_font (blob, data->face_name); |
| 188 if (unlikely (!blob)) | 193 if (unlikely (!blob)) |
| 189 { | 194 { |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 237 memcpy (lf->lfFaceName, face_data->face_name, sizeof (lf->lfFaceName)); | 242 memcpy (lf->lfFaceName, face_data->face_name, sizeof (lf->lfFaceName)); |
| 238 | 243 |
| 239 return true; | 244 return true; |
| 240 } | 245 } |
| 241 | 246 |
| 242 hb_directwrite_shaper_font_data_t * | 247 hb_directwrite_shaper_font_data_t * |
| 243 _hb_directwrite_shaper_font_data_create (hb_font_t *font) | 248 _hb_directwrite_shaper_font_data_create (hb_font_t *font) |
| 244 { | 249 { |
| 245 if (unlikely (!hb_directwrite_shaper_face_data_ensure (font->face))) return NU
LL; | 250 if (unlikely (!hb_directwrite_shaper_face_data_ensure (font->face))) return NU
LL; |
| 246 | 251 |
| 247 hb_directwrite_shaper_font_data_t *data = (hb_directwrite_shaper_font_data_t *
) calloc (1, sizeof (hb_directwrite_shaper_font_data_t)); | 252 hb_directwrite_shaper_font_data_t *data = |
| 253 (hb_directwrite_shaper_font_data_t *) calloc (1, sizeof (hb_directwrite_shap
er_font_data_t)); |
| 248 if (unlikely (!data)) | 254 if (unlikely (!data)) |
| 249 return NULL; | 255 return NULL; |
| 250 | 256 |
| 251 data->hdc = GetDC (NULL); | 257 data->hdc = GetDC (NULL); |
| 252 | 258 |
| 253 if (unlikely (!populate_log_font (&data->log_font, font))) { | 259 if (unlikely (!populate_log_font (&data->log_font, font))) |
| 260 { |
| 254 DEBUG_MSG (DIRECTWRITE, font, "Font populate_log_font() failed"); | 261 DEBUG_MSG (DIRECTWRITE, font, "Font populate_log_font() failed"); |
| 255 _hb_directwrite_shaper_font_data_destroy (data); | 262 _hb_directwrite_shaper_font_data_destroy (data); |
| 256 return NULL; | 263 return NULL; |
| 257 } | 264 } |
| 258 | 265 |
| 259 data->hfont = CreateFontIndirectW (&data->log_font); | 266 data->hfont = CreateFontIndirectW (&data->log_font); |
| 260 if (unlikely (!data->hfont)) { | 267 if (unlikely (!data->hfont)) |
| 268 { |
| 261 DEBUG_MSG (DIRECTWRITE, font, "Font CreateFontIndirectW() failed"); | 269 DEBUG_MSG (DIRECTWRITE, font, "Font CreateFontIndirectW() failed"); |
| 262 _hb_directwrite_shaper_font_data_destroy (data); | 270 _hb_directwrite_shaper_font_data_destroy (data); |
| 263 return NULL; | 271 return NULL; |
| 264 } | 272 } |
| 265 | 273 |
| 266 if (!SelectObject (data->hdc, data->hfont)) { | 274 if (!SelectObject (data->hdc, data->hfont)) |
| 275 { |
| 267 DEBUG_MSG (DIRECTWRITE, font, "Font SelectObject() failed"); | 276 DEBUG_MSG (DIRECTWRITE, font, "Font SelectObject() failed"); |
| 268 _hb_directwrite_shaper_font_data_destroy (data); | 277 _hb_directwrite_shaper_font_data_destroy (data); |
| 269 return NULL; | 278 return NULL; |
| 270 } | 279 } |
| 271 | 280 |
| 272 return data; | 281 return data; |
| 273 } | 282 } |
| 274 | 283 |
| 275 void | 284 void |
| 276 _hb_directwrite_shaper_font_data_destroy (hb_directwrite_shaper_font_data_t *dat
a) | 285 _hb_directwrite_shaper_font_data_destroy (hb_directwrite_shaper_font_data_t *dat
a) |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 public: | 335 public: |
| 327 | 336 |
| 328 IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) { return S_OK
; } | 337 IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) { return S_OK
; } |
| 329 IFACEMETHOD_(ULONG, AddRef)() { return 1; } | 338 IFACEMETHOD_(ULONG, AddRef)() { return 1; } |
| 330 IFACEMETHOD_(ULONG, Release)() { return 1; } | 339 IFACEMETHOD_(ULONG, Release)() { return 1; } |
| 331 | 340 |
| 332 // A single contiguous run of characters containing the same analysis | 341 // A single contiguous run of characters containing the same analysis |
| 333 // results. | 342 // results. |
| 334 struct Run | 343 struct Run |
| 335 { | 344 { |
| 336 UINT32 mTextStart; // starting text position of this run | 345 uint32_t mTextStart; // starting text position of this run |
| 337 UINT32 mTextLength; // number of contiguous code units covered | 346 uint32_t mTextLength; // number of contiguous code units covered |
| 338 UINT32 mGlyphStart; // starting glyph in the glyphs array | 347 uint32_t mGlyphStart; // starting glyph in the glyphs array |
| 339 UINT32 mGlyphCount; // number of glyphs associated with this run of | 348 uint32_t mGlyphCount; // number of glyphs associated with this run of |
| 340 // text | 349 // text |
| 341 DWRITE_SCRIPT_ANALYSIS mScript; | 350 DWRITE_SCRIPT_ANALYSIS mScript; |
| 342 UINT8 mBidiLevel; | 351 uint8_t mBidiLevel; |
| 343 bool mIsSideways; | 352 bool mIsSideways; |
| 344 | 353 |
| 345 inline bool ContainsTextPosition(UINT32 aTextPosition) const | 354 inline bool ContainsTextPosition(uint32_t aTextPosition) const |
| 346 { | 355 { |
| 347 return aTextPosition >= mTextStart | 356 return aTextPosition >= mTextStart |
| 348 && aTextPosition < mTextStart + mTextLength; | 357 && aTextPosition < mTextStart + mTextLength; |
| 349 } | 358 } |
| 350 | 359 |
| 351 Run *nextRun; | 360 Run *nextRun; |
| 352 }; | 361 }; |
| 353 | 362 |
| 354 public: | 363 public: |
| 355 TextAnalysis(const wchar_t* text, | 364 TextAnalysis(const wchar_t* text, |
| 356 UINT32 textLength, | 365 uint32_t textLength, |
| 357 const wchar_t* localeName, | 366 const wchar_t* localeName, |
| 358 DWRITE_READING_DIRECTION readingDirection) | 367 DWRITE_READING_DIRECTION readingDirection) |
| 359 : mText(text) | 368 : mText(text) |
| 360 , mTextLength(textLength) | 369 , mTextLength(textLength) |
| 361 , mLocaleName(localeName) | 370 , mLocaleName(localeName) |
| 362 , mReadingDirection(readingDirection) | 371 , mReadingDirection(readingDirection) |
| 363 , mCurrentRun(NULL) { }; | 372 , mCurrentRun(NULL) { }; |
| 364 | 373 |
| 365 ~TextAnalysis() { | 374 ~TextAnalysis() { |
| 366 // delete runs, except mRunHead which is part of the TextAnalysis object | 375 // delete runs, except mRunHead which is part of the TextAnalysis object |
| 367 for (Run *run = mRunHead.nextRun; run;) { | 376 for (Run *run = mRunHead.nextRun; run;) { |
| 368 Run *origRun = run; | 377 Run *origRun = run; |
| 369 run = run->nextRun; | 378 run = run->nextRun; |
| 370 delete origRun; | 379 free (origRun); |
| 371 } | 380 } |
| 372 } | 381 } |
| 373 | 382 |
| 374 STDMETHODIMP GenerateResults(IDWriteTextAnalyzer* textAnalyzer, | 383 STDMETHODIMP GenerateResults(IDWriteTextAnalyzer* textAnalyzer, |
| 375 Run **runHead) { | 384 Run **runHead) { |
| 376 // Analyzes the text using the script analyzer and returns | 385 // Analyzes the text using the script analyzer and returns |
| 377 // the result as a series of runs. | 386 // the result as a series of runs. |
| 378 | 387 |
| 379 HRESULT hr = S_OK; | 388 HRESULT hr = S_OK; |
| 380 | 389 |
| 381 // Initially start out with one result that covers the entire range. | 390 // Initially start out with one result that covers the entire range. |
| 382 // This result will be subdivided by the analysis processes. | 391 // This result will be subdivided by the analysis processes. |
| 383 mRunHead.mTextStart = 0; | 392 mRunHead.mTextStart = 0; |
| 384 mRunHead.mTextLength = mTextLength; | 393 mRunHead.mTextLength = mTextLength; |
| 385 mRunHead.mBidiLevel = | 394 mRunHead.mBidiLevel = |
| 386 (mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT); | 395 (mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT); |
| 387 mRunHead.nextRun = NULL; | 396 mRunHead.nextRun = NULL; |
| 388 mCurrentRun = &mRunHead; | 397 mCurrentRun = &mRunHead; |
| 389 | 398 |
| 390 // Call each of the analyzers in sequence, recording their results. | 399 // Call each of the analyzers in sequence, recording their results. |
| 391 if (SUCCEEDED(hr = textAnalyzer->AnalyzeScript(this, | 400 if (SUCCEEDED (hr = textAnalyzer->AnalyzeScript (this, 0, mTextLength, this)
)) { |
| 392 0, | |
| 393 mTextLength, | |
| 394 this))) { | |
| 395 *runHead = &mRunHead; | 401 *runHead = &mRunHead; |
| 396 } | 402 } |
| 397 | 403 |
| 398 return hr; | 404 return hr; |
| 399 } | 405 } |
| 400 | 406 |
| 401 // IDWriteTextAnalysisSource implementation | 407 // IDWriteTextAnalysisSource implementation |
| 402 | 408 |
| 403 IFACEMETHODIMP GetTextAtPosition(UINT32 textPosition, | 409 IFACEMETHODIMP GetTextAtPosition(uint32_t textPosition, |
| 404 OUT WCHAR const** textString, | 410 OUT wchar_t const** textString, |
| 405 OUT UINT32* textLength) | 411 OUT uint32_t* textLength) |
| 406 { | 412 { |
| 407 if (textPosition >= mTextLength) { | 413 if (textPosition >= mTextLength) { |
| 408 // No text at this position, valid query though. | 414 // No text at this position, valid query though. |
| 409 *textString = NULL; | 415 *textString = NULL; |
| 410 *textLength = 0; | 416 *textLength = 0; |
| 411 } | 417 } |
| 412 else { | 418 else { |
| 413 *textString = mText + textPosition; | 419 *textString = mText + textPosition; |
| 414 *textLength = mTextLength - textPosition; | 420 *textLength = mTextLength - textPosition; |
| 415 } | 421 } |
| 416 return S_OK; | 422 return S_OK; |
| 417 } | 423 } |
| 418 | 424 |
| 419 IFACEMETHODIMP GetTextBeforePosition(UINT32 textPosition, | 425 IFACEMETHODIMP GetTextBeforePosition(uint32_t textPosition, |
| 420 OUT WCHAR const** textString, | 426 OUT wchar_t const** textString, |
| 421 OUT UINT32* textLength) | 427 OUT uint32_t* textLength) |
| 422 { | 428 { |
| 423 if (textPosition == 0 || textPosition > mTextLength) { | 429 if (textPosition == 0 || textPosition > mTextLength) { |
| 424 // Either there is no text before here (== 0), or this | 430 // Either there is no text before here (== 0), or this |
| 425 // is an invalid position. The query is considered valid thouh. | 431 // is an invalid position. The query is considered valid thouh. |
| 426 *textString = NULL; | 432 *textString = NULL; |
| 427 *textLength = 0; | 433 *textLength = 0; |
| 428 } | 434 } |
| 429 else { | 435 else { |
| 430 *textString = mText; | 436 *textString = mText; |
| 431 *textLength = textPosition; | 437 *textLength = textPosition; |
| 432 } | 438 } |
| 433 return S_OK; | 439 return S_OK; |
| 434 } | 440 } |
| 435 | 441 |
| 436 IFACEMETHODIMP_(DWRITE_READING_DIRECTION) | 442 IFACEMETHODIMP_(DWRITE_READING_DIRECTION) |
| 437 GetParagraphReadingDirection() { return mReadingDirection; } | 443 GetParagraphReadingDirection() { return mReadingDirection; } |
| 438 | 444 |
| 439 IFACEMETHODIMP GetLocaleName(UINT32 textPosition, | 445 IFACEMETHODIMP GetLocaleName(uint32_t textPosition, |
| 440 UINT32* textLength, | 446 uint32_t* textLength, |
| 441 WCHAR const** localeName) { | 447 wchar_t const** localeName) { |
| 442 return S_OK; | 448 return S_OK; |
| 443 } | 449 } |
| 444 | 450 |
| 445 IFACEMETHODIMP | 451 IFACEMETHODIMP |
| 446 GetNumberSubstitution(UINT32 textPosition, | 452 GetNumberSubstitution(uint32_t textPosition, |
| 447 OUT UINT32* textLength, | 453 OUT uint32_t* textLength, |
| 448 OUT IDWriteNumberSubstitution** numberSubstitution) | 454 OUT IDWriteNumberSubstitution** numberSubstitution) |
| 449 { | 455 { |
| 450 // We do not support number substitution. | 456 // We do not support number substitution. |
| 451 *numberSubstitution = NULL; | 457 *numberSubstitution = NULL; |
| 452 *textLength = mTextLength - textPosition; | 458 *textLength = mTextLength - textPosition; |
| 453 | 459 |
| 454 return S_OK; | 460 return S_OK; |
| 455 } | 461 } |
| 456 | 462 |
| 457 // IDWriteTextAnalysisSink implementation | 463 // IDWriteTextAnalysisSink implementation |
| 458 | 464 |
| 459 IFACEMETHODIMP | 465 IFACEMETHODIMP |
| 460 SetScriptAnalysis(UINT32 textPosition, | 466 SetScriptAnalysis(uint32_t textPosition, |
| 461 UINT32 textLength, | 467 uint32_t textLength, |
| 462 DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis) | 468 DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis) |
| 463 { | 469 { |
| 464 SetCurrentRun(textPosition); | 470 SetCurrentRun(textPosition); |
| 465 SplitCurrentRun(textPosition); | 471 SplitCurrentRun(textPosition); |
| 466 while (textLength > 0) { | 472 while (textLength > 0) { |
| 467 Run *run = FetchNextRun(&textLength); | 473 Run *run = FetchNextRun(&textLength); |
| 468 run->mScript = *scriptAnalysis; | 474 run->mScript = *scriptAnalysis; |
| 469 } | 475 } |
| 470 | 476 |
| 471 return S_OK; | 477 return S_OK; |
| 472 } | 478 } |
| 473 | 479 |
| 474 IFACEMETHODIMP | 480 IFACEMETHODIMP |
| 475 SetLineBreakpoints(UINT32 textPosition, | 481 SetLineBreakpoints(uint32_t textPosition, |
| 476 UINT32 textLength, | 482 uint32_t textLength, |
| 477 const DWRITE_LINE_BREAKPOINT* lineBreakpoints) { return S_OK; } | 483 const DWRITE_LINE_BREAKPOINT* lineBreakpoints) { return S_OK; } |
| 478 | 484 |
| 479 IFACEMETHODIMP SetBidiLevel(UINT32 textPosition, | 485 IFACEMETHODIMP SetBidiLevel(uint32_t textPosition, |
| 480 UINT32 textLength, | 486 uint32_t textLength, |
| 481 UINT8 explicitLevel, | 487 uint8_t explicitLevel, |
| 482 UINT8 resolvedLevel) { return S_OK; } | 488 uint8_t resolvedLevel) { return S_OK; } |
| 483 | 489 |
| 484 IFACEMETHODIMP | 490 IFACEMETHODIMP |
| 485 SetNumberSubstitution(UINT32 textPosition, | 491 SetNumberSubstitution(uint32_t textPosition, |
| 486 UINT32 textLength, | 492 uint32_t textLength, |
| 487 IDWriteNumberSubstitution* numberSubstitution) { return S_OK; } | 493 IDWriteNumberSubstitution* numberSubstitution) { return S_OK; } |
| 488 | 494 |
| 489 protected: | 495 protected: |
| 490 Run *FetchNextRun(IN OUT UINT32* textLength) | 496 Run *FetchNextRun(IN OUT uint32_t* textLength) |
| 491 { | 497 { |
| 492 // Used by the sink setters, this returns a reference to the next run. | 498 // Used by the sink setters, this returns a reference to the next run. |
| 493 // Position and length are adjusted to now point after the current run | 499 // Position and length are adjusted to now point after the current run |
| 494 // being returned. | 500 // being returned. |
| 495 | 501 |
| 496 Run *origRun = mCurrentRun; | 502 Run *origRun = mCurrentRun; |
| 497 // Split the tail if needed (the length remaining is less than the | 503 // Split the tail if needed (the length remaining is less than the |
| 498 // current run's size). | 504 // current run's size). |
| 499 if (*textLength < mCurrentRun->mTextLength) { | 505 if (*textLength < mCurrentRun->mTextLength) { |
| 500 SplitCurrentRun(mCurrentRun->mTextStart + *textLength); | 506 SplitCurrentRun(mCurrentRun->mTextStart + *textLength); |
| 501 } | 507 } |
| 502 else { | 508 else { |
| 503 // Just advance the current run. | 509 // Just advance the current run. |
| 504 mCurrentRun = mCurrentRun->nextRun; | 510 mCurrentRun = mCurrentRun->nextRun; |
| 505 } | 511 } |
| 506 *textLength -= origRun->mTextLength; | 512 *textLength -= origRun->mTextLength; |
| 507 | 513 |
| 508 // Return a reference to the run that was just current. | 514 // Return a reference to the run that was just current. |
| 509 return origRun; | 515 return origRun; |
| 510 } | 516 } |
| 511 | 517 |
| 512 void SetCurrentRun(UINT32 textPosition) | 518 void SetCurrentRun(uint32_t textPosition) |
| 513 { | 519 { |
| 514 // Move the current run to the given position. | 520 // Move the current run to the given position. |
| 515 // Since the analyzers generally return results in a forward manner, | 521 // Since the analyzers generally return results in a forward manner, |
| 516 // this will usually just return early. If not, find the | 522 // this will usually just return early. If not, find the |
| 517 // corresponding run for the text position. | 523 // corresponding run for the text position. |
| 518 | 524 |
| 519 if (mCurrentRun && mCurrentRun->ContainsTextPosition(textPosition)) { | 525 if (mCurrentRun && mCurrentRun->ContainsTextPosition(textPosition)) { |
| 520 return; | 526 return; |
| 521 } | 527 } |
| 522 | 528 |
| 523 for (Run *run = &mRunHead; run; run = run->nextRun) { | 529 for (Run *run = &mRunHead; run; run = run->nextRun) { |
| 524 if (run->ContainsTextPosition(textPosition)) { | 530 if (run->ContainsTextPosition(textPosition)) { |
| 525 mCurrentRun = run; | 531 mCurrentRun = run; |
| 526 return; | 532 return; |
| 527 } | 533 } |
| 528 } | 534 } |
| 529 //NS_NOTREACHED("We should always be able to find the text position in one \ | 535 //NS_NOTREACHED("We should always be able to find the text position in one \ |
| 530 // of our runs"); | 536 // of our runs"); |
| 531 } | 537 } |
| 532 | 538 |
| 533 void SplitCurrentRun(UINT32 splitPosition) | 539 void SplitCurrentRun(uint32_t splitPosition) |
| 534 { | 540 { |
| 535 if (!mCurrentRun) { | 541 if (!mCurrentRun) { |
| 536 //NS_ASSERTION(false, "SplitCurrentRun called without current run."); | 542 //NS_ASSERTION(false, "SplitCurrentRun called without current run."); |
| 537 // Shouldn't be calling this when no current run is set! | 543 // Shouldn't be calling this when no current run is set! |
| 538 return; | 544 return; |
| 539 } | 545 } |
| 540 // Split the current run. | 546 // Split the current run. |
| 541 if (splitPosition <= mCurrentRun->mTextStart) { | 547 if (splitPosition <= mCurrentRun->mTextStart) { |
| 542 // No need to split, already the start of a run | 548 // No need to split, already the start of a run |
| 543 // or before it. Usually the first. | 549 // or before it. Usually the first. |
| 544 return; | 550 return; |
| 545 } | 551 } |
| 546 Run *newRun = new Run; | 552 Run *newRun = (Run*) malloc (sizeof (Run)); |
| 547 | 553 |
| 548 *newRun = *mCurrentRun; | 554 *newRun = *mCurrentRun; |
| 549 | 555 |
| 550 // Insert the new run in our linked list. | 556 // Insert the new run in our linked list. |
| 551 newRun->nextRun = mCurrentRun->nextRun; | 557 newRun->nextRun = mCurrentRun->nextRun; |
| 552 mCurrentRun->nextRun = newRun; | 558 mCurrentRun->nextRun = newRun; |
| 553 | 559 |
| 554 // Adjust runs' text positions and lengths. | 560 // Adjust runs' text positions and lengths. |
| 555 UINT32 splitPoint = splitPosition - mCurrentRun->mTextStart; | 561 uint32_t splitPoint = splitPosition - mCurrentRun->mTextStart; |
| 556 newRun->mTextStart += splitPoint; | 562 newRun->mTextStart += splitPoint; |
| 557 newRun->mTextLength -= splitPoint; | 563 newRun->mTextLength -= splitPoint; |
| 558 mCurrentRun->mTextLength = splitPoint; | 564 mCurrentRun->mTextLength = splitPoint; |
| 559 mCurrentRun = newRun; | 565 mCurrentRun = newRun; |
| 560 } | 566 } |
| 561 | 567 |
| 562 protected: | 568 protected: |
| 563 // Input | 569 // Input |
| 564 // (weak references are fine here, since this class is a transient | 570 // (weak references are fine here, since this class is a transient |
| 565 // stack-based helper that doesn't need to copy data) | 571 // stack-based helper that doesn't need to copy data) |
| 566 UINT32 mTextLength; | 572 uint32_t mTextLength; |
| 567 const WCHAR* mText; | 573 const wchar_t* mText; |
| 568 const WCHAR* mLocaleName; | 574 const wchar_t* mLocaleName; |
| 569 DWRITE_READING_DIRECTION mReadingDirection; | 575 DWRITE_READING_DIRECTION mReadingDirection; |
| 570 | 576 |
| 571 // Current processing state. | 577 // Current processing state. |
| 572 Run *mCurrentRun; | 578 Run *mCurrentRun; |
| 573 | 579 |
| 574 // Output is a list of runs starting here | 580 // Output is a list of runs starting here |
| 575 Run mRunHead; | 581 Run mRunHead; |
| 576 }; | 582 }; |
| 577 | 583 |
| 584 static inline uint16_t hb_uint16_swap (const uint16_t v) |
| 585 { return (v >> 8) | (v << 8); } |
| 586 static inline uint32_t hb_uint32_swap (const uint32_t v) |
| 587 { return (hb_uint16_swap(v) << 16) | hb_uint16_swap(v >> 16); } |
| 578 | 588 |
| 579 /* | 589 /* |
| 580 * shaper | 590 * shaper |
| 581 */ | 591 */ |
| 582 | 592 |
| 583 hb_bool_t | 593 hb_bool_t |
| 584 _hb_directwrite_shape(hb_shape_plan_t *shape_plan, | 594 _hb_directwrite_shape(hb_shape_plan_t *shape_plan, |
| 585 hb_font_t *font, | 595 hb_font_t *font, |
| 586 hb_buffer_t *buffer, | 596 hb_buffer_t *buffer, |
| 587 const hb_feature_t *features, | 597 const hb_feature_t *features, |
| 588 unsigned int num_features) | 598 unsigned int num_features) |
| 589 { | 599 { |
| 590 hb_face_t *face = font->face; | 600 hb_face_t *face = font->face; |
| 591 hb_directwrite_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); | 601 hb_directwrite_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); |
| 592 hb_directwrite_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); | 602 hb_directwrite_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); |
| 593 | 603 |
| 594 // factory probably should be cached | 604 // factory probably should be cached |
| 605 #ifndef HB_DIRECTWRITE_EXPERIMENTAL_JUSTIFICATION |
| 595 IDWriteFactory* dwriteFactory; | 606 IDWriteFactory* dwriteFactory; |
| 596 DWriteCreateFactory( | 607 #else |
| 608 IDWriteFactory1* dwriteFactory; |
| 609 #endif |
| 610 DWriteCreateFactory ( |
| 597 DWRITE_FACTORY_TYPE_SHARED, | 611 DWRITE_FACTORY_TYPE_SHARED, |
| 598 __uuidof(IDWriteFactory), | 612 __uuidof (IDWriteFactory), |
| 599 reinterpret_cast<IUnknown**>(&dwriteFactory) | 613 (IUnknown**) &dwriteFactory |
| 600 ); | 614 ); |
| 601 | 615 |
| 602 IDWriteGdiInterop *gdiInterop; | 616 IDWriteGdiInterop *gdiInterop; |
| 603 dwriteFactory->GetGdiInterop (&gdiInterop); | 617 dwriteFactory->GetGdiInterop (&gdiInterop); |
| 604 IDWriteFontFace* fontFace; | 618 IDWriteFontFace* fontFace; |
| 605 gdiInterop->CreateFontFaceFromHdc (font_data->hdc, &fontFace); | 619 gdiInterop->CreateFontFaceFromHdc (font_data->hdc, &fontFace); |
| 606 | 620 |
| 621 #ifndef HB_DIRECTWRITE_EXPERIMENTAL_JUSTIFICATION |
| 607 IDWriteTextAnalyzer* analyzer; | 622 IDWriteTextAnalyzer* analyzer; |
| 608 dwriteFactory->CreateTextAnalyzer (&analyzer); | 623 dwriteFactory->CreateTextAnalyzer(&analyzer); |
| 624 #else |
| 625 IDWriteTextAnalyzer* analyzer0; |
| 626 dwriteFactory->CreateTextAnalyzer (&analyzer0); |
| 627 IDWriteTextAnalyzer1* analyzer = (IDWriteTextAnalyzer1*) analyzer0; |
| 628 #endif |
| 609 | 629 |
| 610 unsigned int scratch_size; | 630 unsigned int scratch_size; |
| 611 hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_
size); | 631 hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_
size); |
| 612 #define ALLOCATE_ARRAY(Type, name, len) \ | 632 #define ALLOCATE_ARRAY(Type, name, len) \ |
| 613 Type *name = (Type *) scratch; \ | 633 Type *name = (Type *) scratch; \ |
| 614 { \ | 634 { \ |
| 615 unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch))
; \ | 635 unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch))
; \ |
| 616 assert (_consumed <= scratch_size); \ | 636 assert (_consumed <= scratch_size); \ |
| 617 scratch += _consumed; \ | 637 scratch += _consumed; \ |
| 618 scratch_size -= _consumed; \ | 638 scratch_size -= _consumed; \ |
| 619 } | 639 } |
| 620 | 640 |
| 621 #define utf16_index() var1.u32 | 641 #define utf16_index() var1.u32 |
| 622 | 642 |
| 623 ALLOCATE_ARRAY(WCHAR, pchars, buffer->len * 2); | 643 ALLOCATE_ARRAY(wchar_t, textString, buffer->len * 2); |
| 624 | 644 |
| 625 unsigned int chars_len = 0; | 645 unsigned int chars_len = 0; |
| 626 for (unsigned int i = 0; i < buffer->len; i++) | 646 for (unsigned int i = 0; i < buffer->len; i++) |
| 627 { | 647 { |
| 628 hb_codepoint_t c = buffer->info[i].codepoint; | 648 hb_codepoint_t c = buffer->info[i].codepoint; |
| 629 buffer->info[i].utf16_index() = chars_len; | 649 buffer->info[i].utf16_index() = chars_len; |
| 630 if (likely(c <= 0xFFFFu)) | 650 if (likely(c <= 0xFFFFu)) |
| 631 pchars[chars_len++] = c; | 651 textString[chars_len++] = c; |
| 632 else if (unlikely(c > 0x10FFFFu)) | 652 else if (unlikely(c > 0x10FFFFu)) |
| 633 pchars[chars_len++] = 0xFFFDu; | 653 textString[chars_len++] = 0xFFFDu; |
| 634 else { | 654 else { |
| 635 pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10); | 655 textString[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10); |
| 636 pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1)); | 656 textString[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1)); |
| 637 } | 657 } |
| 638 } | 658 } |
| 639 | 659 |
| 640 ALLOCATE_ARRAY(WORD, log_clusters, chars_len); | 660 ALLOCATE_ARRAY(WORD, log_clusters, chars_len); |
| 641 if (num_features) | 661 // if (num_features) |
| 642 { | 662 { |
| 643 /* Need log_clusters to assign features. */ | 663 /* Need log_clusters to assign features. */ |
| 644 chars_len = 0; | 664 chars_len = 0; |
| 645 for (unsigned int i = 0; i < buffer->len; i++) | 665 for (unsigned int i = 0; i < buffer->len; i++) |
| 646 { | 666 { |
| 647 hb_codepoint_t c = buffer->info[i].codepoint; | 667 hb_codepoint_t c = buffer->info[i].codepoint; |
| 648 unsigned int cluster = buffer->info[i].cluster; | 668 unsigned int cluster = buffer->info[i].cluster; |
| 649 log_clusters[chars_len++] = cluster; | 669 log_clusters[chars_len++] = cluster; |
| 650 if (hb_in_range(c, 0x10000u, 0x10FFFFu)) | 670 if (hb_in_range(c, 0x10000u, 0x10FFFFu)) |
| 651 log_clusters[chars_len++] = cluster; /* Surrogates. */ | 671 log_clusters[chars_len++] = cluster; /* Surrogates. */ |
| 652 } | 672 } |
| 653 } | 673 } |
| 654 | 674 |
| 655 HRESULT hr; | 675 HRESULT hr; |
| 656 // TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES | 676 // TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES |
| 657 | 677 |
| 658 DWRITE_READING_DIRECTION readingDirection = buffer->props.direction ? | 678 DWRITE_READING_DIRECTION readingDirection = buffer->props.direction ? |
| 659 DWRITE_READING_DIRECTION_RIGHT_TO_LEFT : | 679 DWRITE_READING_DIRECTION_RIGHT_TO_LEFT : |
| 660 DWRITE_READING_DIRECTION_LEFT_TO_RIGHT; | 680 DWRITE_READING_DIRECTION_LEFT_TO_RIGHT; |
| 661 | 681 |
| 662 /* | 682 /* |
| 663 * There's an internal 16-bit limit on some things inside the analyzer, | 683 * There's an internal 16-bit limit on some things inside the analyzer, |
| 664 * but we never attempt to shape a word longer than 64K characters | 684 * but we never attempt to shape a word longer than 64K characters |
| 665 * in a single gfxShapedWord, so we cannot exceed that limit. | 685 * in a single gfxShapedWord, so we cannot exceed that limit. |
| 666 */ | 686 */ |
| 667 UINT32 length = buffer->len; | 687 uint32_t textLength = buffer->len; |
| 668 | 688 |
| 669 TextAnalysis analysis(pchars, length, NULL, readingDirection); | 689 TextAnalysis analysis(textString, textLength, NULL, readingDirection); |
| 670 TextAnalysis::Run *runHead; | 690 TextAnalysis::Run *runHead; |
| 671 hr = analysis.GenerateResults(analyzer, &runHead); | 691 hr = analysis.GenerateResults(analyzer, &runHead); |
| 672 | 692 |
| 673 if (FAILED(hr)) { | 693 #define FAIL(...) \ |
| 674 //NS_WARNING("Analyzer failed to generate results."); | 694 HB_STMT_START { \ |
| 675 return false; | 695 DEBUG_MSG (DIRECTWRITE, NULL, __VA_ARGS__); \ |
| 676 } | 696 return false; \ |
| 677 | 697 } HB_STMT_END; |
| 678 UINT32 maxGlyphs = 3 * length / 2 + 16; | 698 |
| 679 | 699 if (FAILED (hr)) |
| 680 #define INITIAL_GLYPH_SIZE 400 | 700 { |
| 681 UINT16* clusters = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16)); | 701 FAIL ("Analyzer failed to generate results."); |
| 682 UINT16* glyphs = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16)); | 702 return false; |
| 703 } |
| 704 |
| 705 uint32_t maxGlyphCount = 3 * textLength / 2 + 16; |
| 706 uint32_t glyphCount; |
| 707 bool isRightToLeft = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); |
| 708 |
| 709 const wchar_t localeName[20] = {0}; |
| 710 if (buffer->props.language != NULL) |
| 711 { |
| 712 mbstowcs ((wchar_t*) localeName, |
| 713 hb_language_to_string (buffer->props.language), 20); |
| 714 } |
| 715 |
| 716 DWRITE_TYPOGRAPHIC_FEATURES singleFeatures; |
| 717 singleFeatures.featureCount = num_features; |
| 718 if (num_features) |
| 719 { |
| 720 DWRITE_FONT_FEATURE* dwfeatureArray = (DWRITE_FONT_FEATURE*) |
| 721 malloc (sizeof (DWRITE_FONT_FEATURE) * num_features); |
| 722 for (unsigned int i = 0; i < num_features; ++i) |
| 723 { |
| 724 dwfeatureArray[i].nameTag = (DWRITE_FONT_FEATURE_TAG) |
| 725 hb_uint32_swap (features[i].tag); |
| 726 dwfeatureArray[i].parameter = features[i].value; |
| 727 } |
| 728 singleFeatures.features = dwfeatureArray; |
| 729 } |
| 730 const DWRITE_TYPOGRAPHIC_FEATURES* dwFeatures = |
| 731 (const DWRITE_TYPOGRAPHIC_FEATURES*) &singleFeatures; |
| 732 const uint32_t featureRangeLengths[] = { textLength }; |
| 733 |
| 734 retry_getglyphs: |
| 735 uint16_t* clusterMap = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t)); |
| 736 uint16_t* glyphIndices = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t)
); |
| 683 DWRITE_SHAPING_TEXT_PROPERTIES* textProperties = (DWRITE_SHAPING_TEXT_PROPERTI
ES*) | 737 DWRITE_SHAPING_TEXT_PROPERTIES* textProperties = (DWRITE_SHAPING_TEXT_PROPERTI
ES*) |
| 684 malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_TEXT_PROPERTIES)); | 738 malloc (maxGlyphCount * sizeof (DWRITE_SHAPING_TEXT_PROPERTIES)); |
| 685 DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties = (DWRITE_SHAPING_GLYPH_PROPE
RTIES*) | 739 DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties = (DWRITE_SHAPING_GLYPH_PROPE
RTIES*) |
| 686 malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES)); | 740 malloc (maxGlyphCount * sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES)); |
| 687 | 741 |
| 688 UINT32 actualGlyphs; | 742 hr = analyzer->GetGlyphs (textString, textLength, fontFace, FALSE, |
| 689 | 743 isRightToLeft, &runHead->mScript, localeName, NULL, &dwFeatures, |
| 690 bool backward = HB_DIRECTION_IS_BACKWARD(buffer->props.direction); | 744 featureRangeLengths, 1, maxGlyphCount, clusterMap, textProperties, glyphIndi
ces, |
| 691 | 745 glyphProperties, &glyphCount); |
| 692 wchar_t lang[4]; | 746 |
| 693 mbstowcs(lang, hb_language_to_string(buffer->props.language), 4); | 747 if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER))) |
| 694 hr = analyzer->GetGlyphs(pchars, length, | 748 { |
| 695 fontFace, FALSE, | 749 free (clusterMap); |
| 696 buffer->props.direction, | 750 free (glyphIndices); |
| 697 &runHead->mScript, (const wchar_t*)lang, NULL, NULL, NULL, 0, | 751 free (textProperties); |
| 698 maxGlyphs, clusters, textProperties, | 752 free (glyphProperties); |
| 699 glyphs, glyphProperties, &actualGlyphs); | 753 |
| 700 | 754 maxGlyphCount *= 2; |
| 701 if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) { | 755 |
| 702 free(clusters); | 756 goto retry_getglyphs; |
| 703 free(glyphs); | 757 } |
| 704 free(textProperties); | 758 if (FAILED (hr)) |
| 705 free(glyphProperties); | 759 { |
| 706 | 760 FAIL ("Analyzer failed to get glyphs."); |
| 707 clusters = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16)); | 761 return false; |
| 708 glyphs = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16)); | 762 } |
| 709 textProperties = (DWRITE_SHAPING_TEXT_PROPERTIES*) | 763 |
| 710 malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_TEXT_PROPERTIES)); | 764 float* glyphAdvances = (float*) malloc (maxGlyphCount * sizeof (float)); |
| 711 glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*) | 765 DWRITE_GLYPH_OFFSET* glyphOffsets = (DWRITE_GLYPH_OFFSET*) |
| 712 malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES)); | 766 malloc(maxGlyphCount * sizeof (DWRITE_GLYPH_OFFSET)); |
| 713 | |
| 714 hr = analyzer->GetGlyphs(pchars, length, | |
| 715 fontFace, FALSE, | |
| 716 buffer->props.direction, | |
| 717 &runHead->mScript, (const wchar_t*)lang, NULL, NULL, NULL, 0, | |
| 718 maxGlyphs, clusters, textProperties, | |
| 719 glyphs, glyphProperties, &actualGlyphs); | |
| 720 } | |
| 721 if (FAILED(hr)) { | |
| 722 //NS_WARNING("Analyzer failed to get glyphs."); | |
| 723 return false; | |
| 724 } | |
| 725 | |
| 726 FLOAT advances[400]; | |
| 727 DWRITE_GLYPH_OFFSET offsets[400]; | |
| 728 | |
| 729 | 767 |
| 730 /* The -2 in the following is to compensate for possible | 768 /* The -2 in the following is to compensate for possible |
| 731 * alignment needed after the WORD array. sizeof(WORD) == 2. */ | 769 * alignment needed after the WORD array. sizeof(WORD) == 2. */ |
| 732 unsigned int glyphs_size = (scratch_size * sizeof (int)-2) | 770 unsigned int glyphs_size = (scratch_size * sizeof(int) - 2) |
| 733 / (sizeof (WORD) + | 771 / (sizeof(WORD) + |
| 734 4 + // sizeof (SCRIPT_GLYPHPROP) + | 772 sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES) + |
| 735 sizeof (int) + | 773 sizeof(int) + |
| 736 8 + // sizeof (GOFFSET) + | 774 sizeof(DWRITE_GLYPH_OFFSET) + |
| 737 sizeof (uint32_t)); | 775 sizeof(uint32_t)); |
| 738 ALLOCATE_ARRAY(uint32_t, vis_clusters, glyphs_size); | 776 ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size); |
| 739 | 777 |
| 740 #undef ALLOCATE_ARRAY | 778 #undef ALLOCATE_ARRAY |
| 741 | 779 |
| 742 hr = analyzer->GetGlyphPlacements(pchars, | 780 int fontEmSize = font->face->get_upem(); |
| 743 clusters, | 781 if (fontEmSize < 0) |
| 744 textProperties, | 782 fontEmSize = -fontEmSize; |
| 745 length, | 783 |
| 746 glyphs, | 784 if (fontEmSize < 0) |
| 747 glyphProperties, | 785 fontEmSize = -fontEmSize; |
| 748 actualGlyphs, | 786 double x_mult = (double) font->x_scale / fontEmSize; |
| 749 fontFace, | 787 double y_mult = (double) font->y_scale / fontEmSize; |
| 750 face->get_upem(), | 788 |
| 751 FALSE, | 789 hr = analyzer->GetGlyphPlacements (textString, |
| 752 FALSE, | 790 clusterMap, textProperties, textLength, glyphIndices, |
| 753 &runHead->mScript, | 791 glyphProperties, glyphCount, fontFace, fontEmSize, |
| 754 NULL, | 792 FALSE, isRightToLeft, &runHead->mScript, localeName, |
| 755 NULL, | 793 &dwFeatures, featureRangeLengths, 1, |
| 756 NULL, | 794 glyphAdvances, glyphOffsets); |
| 757 0, | 795 |
| 758 advances, | 796 if (FAILED (hr)) |
| 759 offsets); | 797 { |
| 760 | 798 FAIL ("Analyzer failed to get glyph placements."); |
| 761 if (FAILED(hr)) { | 799 return false; |
| 762 //NS_WARNING("Analyzer failed to get glyph placements."); | 800 } |
| 763 return false; | 801 |
| 764 } | 802 #ifdef HB_DIRECTWRITE_EXPERIMENTAL_JUSTIFICATION |
| 765 | 803 |
| 766 unsigned int glyphs_len = actualGlyphs; | 804 DWRITE_JUSTIFICATION_OPPORTUNITY* justificationOpportunities = |
| 805 (DWRITE_JUSTIFICATION_OPPORTUNITY*) |
| 806 malloc (maxGlyphCount * sizeof (DWRITE_JUSTIFICATION_OPPORTUNITY)); |
| 807 hr = analyzer->GetJustificationOpportunities (fontFace, fontEmSize, |
| 808 runHead->mScript, textLength, glyphCount, textString, clusterMap, |
| 809 glyphProperties, justificationOpportunities); |
| 810 |
| 811 if (FAILED (hr)) |
| 812 { |
| 813 FAIL ("Analyzer failed to get justification opportunities."); |
| 814 return false; |
| 815 } |
| 816 |
| 817 // TODO: get lineWith from somewhere |
| 818 float lineWidth = 60000; |
| 819 |
| 820 float* justifiedGlyphAdvances = |
| 821 (float*) malloc (maxGlyphCount * sizeof (float)); |
| 822 DWRITE_GLYPH_OFFSET* justifiedGlyphOffsets = (DWRITE_GLYPH_OFFSET*) |
| 823 malloc (glyphCount * sizeof (DWRITE_GLYPH_OFFSET)); |
| 824 hr = analyzer->JustifyGlyphAdvances (lineWidth, glyphCount, justificationOppor
tunities, |
| 825 glyphAdvances, glyphOffsets, justifiedGlyphAdvances, justifiedGlyphOffsets); |
| 826 |
| 827 if (FAILED (hr)) |
| 828 { |
| 829 FAIL ("Analyzer failed to get justified glyph advances."); |
| 830 return false; |
| 831 } |
| 832 |
| 833 DWRITE_SCRIPT_PROPERTIES scriptProperties; |
| 834 hr = analyzer->GetScriptProperties (runHead->mScript, &scriptProperties); |
| 835 if (FAILED (hr)) |
| 836 { |
| 837 FAIL ("Analyzer failed to get script properties."); |
| 838 return false; |
| 839 } |
| 840 uint32_t justificationCharacter = scriptProperties.justificationCharacter; |
| 841 |
| 842 // if a script justificationCharacter is not space, it can have GetJustifiedGl
yphs |
| 843 if (justificationCharacter != 32) |
| 844 { |
| 845 retry_getjustifiedglyphs: |
| 846 uint16_t* modifiedClusterMap = (uint16_t*) malloc (maxGlyphCount * sizeof (u
int16_t)); |
| 847 uint16_t* modifiedGlyphIndices = (uint16_t*) malloc (maxGlyphCount * sizeof
(uint16_t)); |
| 848 float* modifiedGlyphAdvances = (float*) malloc (maxGlyphCount * sizeof (floa
t)); |
| 849 DWRITE_GLYPH_OFFSET* modifiedGlyphOffsets = (DWRITE_GLYPH_OFFSET*) |
| 850 malloc (maxGlyphCount * sizeof (DWRITE_GLYPH_OFFSET)); |
| 851 uint32_t actualGlyphsCount; |
| 852 hr = analyzer->GetJustifiedGlyphs (fontFace, fontEmSize, runHead->mScript, |
| 853 textLength, glyphCount, maxGlyphCount, clusterMap, glyphIndices, |
| 854 glyphAdvances, justifiedGlyphAdvances, justifiedGlyphOffsets, |
| 855 glyphProperties, &actualGlyphsCount, modifiedClusterMap, modifiedGlyphIn
dices, |
| 856 modifiedGlyphAdvances, modifiedGlyphOffsets); |
| 857 |
| 858 if (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)) |
| 859 { |
| 860 maxGlyphCount = actualGlyphsCount; |
| 861 free (modifiedClusterMap); |
| 862 free (modifiedGlyphIndices); |
| 863 free (modifiedGlyphAdvances); |
| 864 free (modifiedGlyphOffsets); |
| 865 |
| 866 maxGlyphCount = actualGlyphsCount; |
| 867 |
| 868 goto retry_getjustifiedglyphs; |
| 869 } |
| 870 if (FAILED (hr)) |
| 871 { |
| 872 FAIL ("Analyzer failed to get justified glyphs."); |
| 873 return false; |
| 874 } |
| 875 |
| 876 free (clusterMap); |
| 877 free (glyphIndices); |
| 878 free (glyphAdvances); |
| 879 free (glyphOffsets); |
| 880 |
| 881 glyphCount = actualGlyphsCount; |
| 882 clusterMap = modifiedClusterMap; |
| 883 glyphIndices = modifiedGlyphIndices; |
| 884 glyphAdvances = modifiedGlyphAdvances; |
| 885 glyphOffsets = modifiedGlyphOffsets; |
| 886 |
| 887 free(justifiedGlyphAdvances); |
| 888 free(justifiedGlyphOffsets); |
| 889 } |
| 890 else |
| 891 { |
| 892 free(glyphAdvances); |
| 893 free(glyphOffsets); |
| 894 |
| 895 glyphAdvances = justifiedGlyphAdvances; |
| 896 glyphOffsets = justifiedGlyphOffsets; |
| 897 } |
| 898 |
| 899 free(justificationOpportunities); |
| 900 |
| 901 #endif |
| 767 | 902 |
| 768 /* Ok, we've got everything we need, now compose output buffer, | 903 /* Ok, we've got everything we need, now compose output buffer, |
| 769 * very, *very*, carefully! */ | 904 * very, *very*, carefully! */ |
| 770 | 905 |
| 771 /* Calculate visual-clusters. That's what we ship. */ | 906 /* Calculate visual-clusters. That's what we ship. */ |
| 772 for (unsigned int i = 0; i < glyphs_len; i++) | 907 for (unsigned int i = 0; i < glyphCount; i++) |
| 773 vis_clusters[i] = -1; | 908 vis_clusters[i] = -1; |
| 774 for (unsigned int i = 0; i < buffer->len; i++) { | 909 for (unsigned int i = 0; i < buffer->len; i++) |
| 775 uint32_t *p = &vis_clusters[log_clusters[buffer->info[i].utf16_index()]]; | 910 { |
| 776 //*p = MIN (*p, buffer->info[i].cluster); | 911 uint32_t *p = |
| 777 } | 912 &vis_clusters[log_clusters[buffer->info[i].utf16_index()]]; |
| 778 for (unsigned int i = 1; i < glyphs_len; i++) | 913 *p = MIN (*p, buffer->info[i].cluster); |
| 914 } |
| 915 for (unsigned int i = 1; i < glyphCount; i++) |
| 779 if (vis_clusters[i] == -1) | 916 if (vis_clusters[i] == -1) |
| 780 vis_clusters[i] = vis_clusters[i - 1]; | 917 vis_clusters[i] = vis_clusters[i - 1]; |
| 781 | 918 |
| 782 #undef utf16_index | 919 #undef utf16_index |
| 783 | 920 |
| 784 //if (unlikely (!buffer->ensure (glyphs_len))) | 921 if (unlikely (!buffer->ensure (glyphCount))) |
| 785 // FAIL ("Buffer in error"); | 922 FAIL ("Buffer in error"); |
| 786 | 923 |
| 787 #undef FAIL | 924 #undef FAIL |
| 788 | 925 |
| 789 /* Set glyph infos */ | 926 /* Set glyph infos */ |
| 790 buffer->len = 0; | 927 buffer->len = 0; |
| 791 for (unsigned int i = 0; i < glyphs_len; i++) | 928 for (unsigned int i = 0; i < glyphCount; i++) |
| 792 { | 929 { |
| 793 hb_glyph_info_t *info = &buffer->info[buffer->len++]; | 930 hb_glyph_info_t *info = &buffer->info[buffer->len++]; |
| 794 | 931 |
| 795 info->codepoint = glyphs[i]; | 932 info->codepoint = glyphIndices[i]; |
| 796 info->cluster = vis_clusters[i]; | 933 info->cluster = vis_clusters[i]; |
| 797 | 934 |
| 798 /* The rest is crap. Let's store position info there for now. */ | 935 /* The rest is crap. Let's store position info there for now. */ |
| 799 info->mask = advances[i]; | 936 info->mask = glyphAdvances[i]; |
| 800 info->var1.u32 = offsets[i].ascenderOffset; | 937 info->var1.i32 = glyphOffsets[i].advanceOffset; |
| 801 info->var2.u32 = -offsets[i].advanceOffset; | 938 info->var2.i32 = glyphOffsets[i].ascenderOffset; |
| 802 } | 939 } |
| 803 | |
| 804 free(clusters); | |
| 805 free(glyphs); | |
| 806 free(textProperties); | |
| 807 free(glyphProperties); | |
| 808 | 940 |
| 809 /* Set glyph positions */ | 941 /* Set glyph positions */ |
| 810 buffer->clear_positions (); | 942 buffer->clear_positions (); |
| 811 for (unsigned int i = 0; i < glyphs_len; i++) | 943 for (unsigned int i = 0; i < glyphCount; i++) |
| 812 { | 944 { |
| 813 hb_glyph_info_t *info = &buffer->info[i]; | 945 hb_glyph_info_t *info = &buffer->info[i]; |
| 814 hb_glyph_position_t *pos = &buffer->pos[i]; | 946 hb_glyph_position_t *pos = &buffer->pos[i]; |
| 815 | 947 |
| 816 /* TODO vertical */ | 948 /* TODO vertical */ |
| 817 pos->x_advance = info->mask; | 949 pos->x_advance = x_mult * (int32_t) info->mask; |
| 818 pos->x_offset = backward ? -info->var1.u32 : info->var1.u32; | 950 pos->x_offset = |
| 819 pos->y_offset = info->var2.u32; | 951 x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32); |
| 820 } | 952 pos->y_offset = y_mult * info->var2.i32; |
| 821 | 953 } |
| 822 if (backward) | 954 |
| 955 if (isRightToLeft) |
| 823 hb_buffer_reverse (buffer); | 956 hb_buffer_reverse (buffer); |
| 824 | 957 |
| 958 free (clusterMap); |
| 959 free (glyphIndices); |
| 960 free (textProperties); |
| 961 free (glyphProperties); |
| 962 free (glyphAdvances); |
| 963 free (glyphOffsets); |
| 964 |
| 965 if (num_features) |
| 966 free (singleFeatures.features); |
| 967 |
| 825 /* Wow, done! */ | 968 /* Wow, done! */ |
| 826 return true; | 969 return true; |
| 827 } | 970 } |
| OLD | NEW |