diff options
| author | Jason Rumney | 2008-07-29 16:24:24 +0000 |
|---|---|---|
| committer | Jason Rumney | 2008-07-29 16:24:24 +0000 |
| commit | c320e90a79d4b7e92aa091b1ed02d65dd388e54c (patch) | |
| tree | 1ae24c4773cef65fea5fda79402898b10500e9d9 /src | |
| parent | 838d78d411955dbe3ef5d75ff404ced8ca832c5a (diff) | |
| download | emacs-c320e90a79d4b7e92aa091b1ed02d65dd388e54c.tar.gz emacs-c320e90a79d4b7e92aa091b1ed02d65dd388e54c.zip | |
(uniscribe_shape): Avoid using context if cache
is populated.
(uniscribe_encode_char): Always use uniscribe.
Avoid using context if cache is populated.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 7 | ||||
| -rw-r--r-- | src/w32uniscribe.c | 168 |
2 files changed, 122 insertions, 53 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index ad37435c1d5..a0ba987005e 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,10 @@ | |||
| 1 | 2008-07-29 Jason Rumney <jasonr@gnu.org> | ||
| 2 | |||
| 3 | * w32uniscribe.c (uniscribe_shape): Avoid using context if cache | ||
| 4 | is populated. | ||
| 5 | (uniscribe_encode_char): Always use uniscribe. | ||
| 6 | Avoid using context if cache is populated. | ||
| 7 | |||
| 1 | 2008-07-29 Jan Djärv <jan.h.d@swipnet.se> | 8 | 2008-07-29 Jan Djärv <jan.h.d@swipnet.se> |
| 2 | 9 | ||
| 3 | * xmenu.c (Fx_menu_bar_open_internal): Use activate_item signal to | 10 | * xmenu.c (Fx_menu_bar_open_internal): Use activate_item signal to |
diff --git a/src/w32uniscribe.c b/src/w32uniscribe.c index 8315f8814ad..42047c3d3c7 100644 --- a/src/w32uniscribe.c +++ b/src/w32uniscribe.c | |||
| @@ -211,10 +211,10 @@ uniscribe_shape (lgstring) | |||
| 211 | int *advances; | 211 | int *advances; |
| 212 | GOFFSET *offsets; | 212 | GOFFSET *offsets; |
| 213 | ABC overall_metrics; | 213 | ABC overall_metrics; |
| 214 | HDC context; | ||
| 215 | HFONT old_font; | ||
| 216 | HRESULT result; | 214 | HRESULT result; |
| 217 | struct frame * f; | 215 | struct frame * f = NULL; |
| 216 | HDC context = NULL; | ||
| 217 | HFONT old_font = NULL; | ||
| 218 | 218 | ||
| 219 | CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font); | 219 | CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font); |
| 220 | uniscribe_font = (struct uniscribe_font_info *) font; | 220 | uniscribe_font = (struct uniscribe_font_info *) font; |
| @@ -248,7 +248,7 @@ uniscribe_shape (lgstring) | |||
| 248 | sizeof (SCRIPT_ITEM) * max_items + 1); | 248 | sizeof (SCRIPT_ITEM) * max_items + 1); |
| 249 | } | 249 | } |
| 250 | 250 | ||
| 251 | if (!SUCCEEDED (result)) | 251 | if (FAILED (result)) |
| 252 | { | 252 | { |
| 253 | xfree (items); | 253 | xfree (items); |
| 254 | return Qnil; | 254 | return Qnil; |
| @@ -257,10 +257,6 @@ uniscribe_shape (lgstring) | |||
| 257 | /* TODO: When we get BIDI support, we need to call ScriptLayout here. | 257 | /* TODO: When we get BIDI support, we need to call ScriptLayout here. |
| 258 | Requires that we know the surrounding context. */ | 258 | Requires that we know the surrounding context. */ |
| 259 | 259 | ||
| 260 | f = XFRAME (selected_frame); | ||
| 261 | context = get_frame_dc (f); | ||
| 262 | old_font = SelectObject (context, FONT_HANDLE(font)); | ||
| 263 | |||
| 264 | glyphs = alloca (max_glyphs * sizeof (WORD)); | 260 | glyphs = alloca (max_glyphs * sizeof (WORD)); |
| 265 | clusters = alloca (nchars * sizeof (WORD)); | 261 | clusters = alloca (nchars * sizeof (WORD)); |
| 266 | attributes = alloca (max_glyphs * sizeof (SCRIPT_VISATTR)); | 262 | attributes = alloca (max_glyphs * sizeof (SCRIPT_VISATTR)); |
| @@ -272,17 +268,35 @@ uniscribe_shape (lgstring) | |||
| 272 | int nglyphs, nchars_in_run, rtl = items[i].a.fRTL ? -1 : 1; | 268 | int nglyphs, nchars_in_run, rtl = items[i].a.fRTL ? -1 : 1; |
| 273 | nchars_in_run = items[i+1].iCharPos - items[i].iCharPos; | 269 | nchars_in_run = items[i+1].iCharPos - items[i].iCharPos; |
| 274 | 270 | ||
| 271 | /* Context may be NULL here, in which case the cache should be | ||
| 272 | used without needing to select the font. */ | ||
| 275 | result = ScriptShape (context, &(uniscribe_font->cache), | 273 | result = ScriptShape (context, &(uniscribe_font->cache), |
| 276 | chars + items[i].iCharPos, nchars_in_run, | 274 | chars + items[i].iCharPos, nchars_in_run, |
| 277 | max_glyphs - done_glyphs, &(items[i].a), | 275 | max_glyphs - done_glyphs, &(items[i].a), |
| 278 | glyphs, clusters, attributes, &nglyphs); | 276 | glyphs, clusters, attributes, &nglyphs); |
| 277 | |||
| 278 | if (result == E_PENDING && !context) | ||
| 279 | { | ||
| 280 | /* This assumes the selected frame is on the same display as the | ||
| 281 | one we are drawing. It would be better for the frame to be | ||
| 282 | passed in. */ | ||
| 283 | f = XFRAME (selected_frame); | ||
| 284 | context = get_frame_dc (f); | ||
| 285 | old_font = SelectObject (context, FONT_HANDLE(font)); | ||
| 286 | |||
| 287 | result = ScriptShape (context, &(uniscribe_font->cache), | ||
| 288 | chars + items[i].iCharPos, nchars_in_run, | ||
| 289 | max_glyphs - done_glyphs, &(items[i].a), | ||
| 290 | glyphs, clusters, attributes, &nglyphs); | ||
| 291 | } | ||
| 292 | |||
| 279 | if (result == E_OUTOFMEMORY) | 293 | if (result == E_OUTOFMEMORY) |
| 280 | { | 294 | { |
| 281 | /* Need a bigger lgstring. */ | 295 | /* Need a bigger lgstring. */ |
| 282 | lgstring = Qnil; | 296 | lgstring = Qnil; |
| 283 | break; | 297 | break; |
| 284 | } | 298 | } |
| 285 | else if (result) /* Failure. */ | 299 | else if (FAILED (result)) |
| 286 | { | 300 | { |
| 287 | /* Can't shape this run - return results so far if any. */ | 301 | /* Can't shape this run - return results so far if any. */ |
| 288 | break; | 302 | break; |
| @@ -298,7 +312,18 @@ uniscribe_shape (lgstring) | |||
| 298 | result = ScriptPlace (context, &(uniscribe_font->cache), | 312 | result = ScriptPlace (context, &(uniscribe_font->cache), |
| 299 | glyphs, nglyphs, attributes, &(items[i].a), | 313 | glyphs, nglyphs, attributes, &(items[i].a), |
| 300 | advances, offsets, &overall_metrics); | 314 | advances, offsets, &overall_metrics); |
| 301 | if (SUCCEEDED (result)) | 315 | if (result == E_PENDING && !context) |
| 316 | { | ||
| 317 | /* Cache not complete... */ | ||
| 318 | f = XFRAME (selected_frame); | ||
| 319 | context = get_frame_dc (f); | ||
| 320 | old_font = SelectObject (context, FONT_HANDLE(font)); | ||
| 321 | |||
| 322 | result = ScriptPlace (context, &(uniscribe_font->cache), | ||
| 323 | glyphs, nglyphs, attributes, &(items[i].a), | ||
| 324 | advances, offsets, &overall_metrics); | ||
| 325 | } | ||
| 326 | if (SUCCEEDED (result)) | ||
| 302 | { | 327 | { |
| 303 | int j, nclusters, from, to; | 328 | int j, nclusters, from, to; |
| 304 | 329 | ||
| @@ -357,6 +382,16 @@ uniscribe_shape (lgstring) | |||
| 357 | result = ScriptGetGlyphABCWidth (context, | 382 | result = ScriptGetGlyphABCWidth (context, |
| 358 | &(uniscribe_font->cache), | 383 | &(uniscribe_font->cache), |
| 359 | glyphs[j], &char_metric); | 384 | glyphs[j], &char_metric); |
| 385 | if (result == E_PENDING && !context) | ||
| 386 | { | ||
| 387 | /* Cache incomplete... */ | ||
| 388 | f = XFRAME (selected_frame); | ||
| 389 | context = get_frame_dc (f); | ||
| 390 | old_font = SelectObject (context, FONT_HANDLE(font)); | ||
| 391 | result = ScriptGetGlyphABCWidth (context, | ||
| 392 | &(uniscribe_font->cache), | ||
| 393 | glyphs[j], &char_metric); | ||
| 394 | } | ||
| 360 | 395 | ||
| 361 | if (SUCCEEDED (result)) | 396 | if (SUCCEEDED (result)) |
| 362 | { | 397 | { |
| @@ -382,14 +417,19 @@ uniscribe_shape (lgstring) | |||
| 382 | } | 417 | } |
| 383 | else | 418 | else |
| 384 | LGLYPH_SET_ADJUSTMENT (lglyph, Qnil); | 419 | LGLYPH_SET_ADJUSTMENT (lglyph, Qnil); |
| 385 | } } | 420 | } |
| 421 | } | ||
| 386 | } | 422 | } |
| 387 | done_glyphs += nglyphs; | 423 | done_glyphs += nglyphs; |
| 388 | } | 424 | } |
| 389 | 425 | ||
| 390 | xfree (items); | 426 | xfree (items); |
| 391 | SelectObject (context, old_font); | 427 | |
| 392 | release_frame_dc (f, context); | 428 | if (context) |
| 429 | { | ||
| 430 | SelectObject (context, old_font); | ||
| 431 | release_frame_dc (f, context); | ||
| 432 | } | ||
| 393 | 433 | ||
| 394 | if (NILP (lgstring)) | 434 | if (NILP (lgstring)) |
| 395 | return Qnil; | 435 | return Qnil; |
| @@ -405,68 +445,90 @@ uniscribe_encode_char (font, c) | |||
| 405 | struct font *font; | 445 | struct font *font; |
| 406 | int c; | 446 | int c; |
| 407 | { | 447 | { |
| 408 | HDC context; | 448 | HDC context = NULL; |
| 409 | struct frame *f; | 449 | struct frame *f = NULL; |
| 410 | HFONT old_font; | 450 | HFONT old_font = NULL; |
| 411 | unsigned code = FONT_INVALID_CODE; | 451 | unsigned code = FONT_INVALID_CODE; |
| 452 | wchar_t ch[2]; | ||
| 453 | int len; | ||
| 454 | SCRIPT_ITEM* items; | ||
| 455 | int nitems; | ||
| 456 | struct uniscribe_font_info *uniscribe_font | ||
| 457 | = (struct uniscribe_font_info *)font; | ||
| 412 | 458 | ||
| 413 | /* Use selected frame until API is updated to pass the frame. */ | ||
| 414 | f = XFRAME (selected_frame); | ||
| 415 | context = get_frame_dc (f); | ||
| 416 | old_font = SelectObject (context, FONT_HANDLE(font)); | ||
| 417 | |||
| 418 | /* There are a number of ways to get glyph indices for BMP characters. | ||
| 419 | The GetGlyphIndices GDI function seems to work best for detecting | ||
| 420 | non-existing glyphs. */ | ||
| 421 | if (c < 0x10000) | 459 | if (c < 0x10000) |
| 422 | { | 460 | { |
| 423 | wchar_t ch = (wchar_t) c; | 461 | ch[0] = (wchar_t) c; |
| 424 | WORD index; | 462 | len = 1; |
| 425 | DWORD retval = GetGlyphIndicesW (context, &ch, 1, &index, | ||
| 426 | GGI_MARK_NONEXISTING_GLYPHS); | ||
| 427 | if (retval == 1 && index != 0xFFFF) | ||
| 428 | code = index; | ||
| 429 | } | 463 | } |
| 430 | |||
| 431 | /* Non BMP characters must be handled by the uniscribe shaping | ||
| 432 | engine as GDI functions (except blindly displaying lines of | ||
| 433 | unicode text) and the promising looking ScriptGetCMap do not | ||
| 434 | convert surrogate pairs to glyph indexes correctly. */ | ||
| 435 | else | 464 | else |
| 436 | { | 465 | { |
| 437 | wchar_t ch[2]; | ||
| 438 | SCRIPT_ITEM* items; | ||
| 439 | int nitems; | ||
| 440 | struct uniscribe_font_info *uniscribe_font | ||
| 441 | = (struct uniscribe_font_info *)font; | ||
| 442 | DWORD surrogate = c - 0x10000; | 466 | DWORD surrogate = c - 0x10000; |
| 443 | 467 | ||
| 444 | /* High surrogate: U+D800 - U+DBFF. */ | 468 | /* High surrogate: U+D800 - U+DBFF. */ |
| 445 | ch[0] = 0xD800 + ((surrogate >> 10) & 0x03FF); | 469 | ch[0] = 0xD800 + ((surrogate >> 10) & 0x03FF); |
| 446 | /* Low surrogate: U+DC00 - U+DFFF. */ | 470 | /* Low surrogate: U+DC00 - U+DFFF. */ |
| 447 | ch[1] = 0xDC00 + (surrogate & 0x03FF); | 471 | ch[1] = 0xDC00 + (surrogate & 0x03FF); |
| 472 | len = 2; | ||
| 473 | } | ||
| 448 | 474 | ||
| 475 | /* Non BMP characters must be handled by the uniscribe shaping | ||
| 476 | engine as GDI functions (except blindly displaying lines of | ||
| 477 | unicode text) and the promising looking ScriptGetCMap do not | ||
| 478 | convert surrogate pairs to glyph indexes correctly. */ | ||
| 479 | { | ||
| 449 | items = (SCRIPT_ITEM *) alloca (sizeof (SCRIPT_ITEM) * 2 + 1); | 480 | items = (SCRIPT_ITEM *) alloca (sizeof (SCRIPT_ITEM) * 2 + 1); |
| 450 | if (SUCCEEDED (ScriptItemize (ch, 2, 2, NULL, NULL, items, &nitems))) | 481 | if (SUCCEEDED (ScriptItemize (ch, len, 2, NULL, NULL, items, &nitems))) |
| 451 | { | 482 | { |
| 452 | WORD glyphs[2], clusters[2]; | 483 | HRESULT result; |
| 453 | SCRIPT_VISATTR attrs[2]; | 484 | /* Some Indic characters result in more than 1 glyph. */ |
| 485 | WORD glyphs[1], clusters[1]; | ||
| 486 | SCRIPT_VISATTR attrs[1]; | ||
| 454 | int nglyphs; | 487 | int nglyphs; |
| 455 | 488 | ||
| 456 | if (SUCCEEDED (ScriptShape (context, &(uniscribe_font->cache), | 489 | result = ScriptShape (context, &(uniscribe_font->cache), |
| 457 | ch, 2, 2, &(items[0].a), | 490 | ch, len, 20, &(items[0].a), |
| 458 | glyphs, clusters, attrs, &nglyphs)) | 491 | glyphs, clusters, attrs, &nglyphs); |
| 459 | && nglyphs == 1) | 492 | |
| 493 | if (result == E_PENDING) | ||
| 494 | { | ||
| 495 | /* Use selected frame until API is updated to pass | ||
| 496 | the frame. */ | ||
| 497 | f = XFRAME (selected_frame); | ||
| 498 | context = get_frame_dc (f); | ||
| 499 | old_font = SelectObject (context, FONT_HANDLE(font)); | ||
| 500 | result = ScriptShape (context, &(uniscribe_font->cache), | ||
| 501 | ch, len, 2, &(items[0].a), | ||
| 502 | glyphs, clusters, attrs, &nglyphs); | ||
| 503 | } | ||
| 504 | |||
| 505 | if (SUCCEEDED (result) && nglyphs == 1) | ||
| 460 | { | 506 | { |
| 461 | code = glyphs[0]; | 507 | code = glyphs[0]; |
| 462 | } | 508 | } |
| 463 | } | 509 | else if (SUCCEEDED (result) || result == E_OUTOFMEMORY) |
| 510 | { | ||
| 511 | /* This character produces zero or more than one glyph | ||
| 512 | when shaped. But we still need the return from here | ||
| 513 | to be valid for the shaping engine to be invoked | ||
| 514 | later. */ | ||
| 515 | result = ScriptGetCMap (context, &(uniscribe_font->cache), | ||
| 516 | ch, len, 0, glyphs); | ||
| 517 | if (SUCCEEDED (result)) | ||
| 518 | return glyphs[0]; | ||
| 519 | else | ||
| 520 | return 0; /* notdef - enough in some cases to get the script | ||
| 521 | engine working, but not others... */ | ||
| 522 | } | ||
| 523 | } | ||
| 464 | } | 524 | } |
| 525 | if (context) | ||
| 526 | { | ||
| 527 | SelectObject (context, old_font); | ||
| 528 | release_frame_dc (f, context); | ||
| 529 | } | ||
| 465 | 530 | ||
| 466 | SelectObject (context, old_font); | 531 | return code; |
| 467 | release_frame_dc (f, context); | ||
| 468 | |||
| 469 | return code; | ||
| 470 | } | 532 | } |
| 471 | 533 | ||
| 472 | /* | 534 | /* |