Lines 1034-1039
Link Here
|
1034 |
virtual long FillDXArray( long* pDXArray ) const; |
1034 |
virtual long FillDXArray( long* pDXArray ) const; |
1035 |
virtual int GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const; |
1035 |
virtual int GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const; |
1036 |
virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const; |
1036 |
virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const; |
|
|
1037 |
virtual bool IsKashidaPosValid ( int nCharPos ) const; |
1037 |
|
1038 |
|
1038 |
// for glyph+font+script fallback |
1039 |
// for glyph+font+script fallback |
1039 |
virtual void MoveGlyph( int nStart, long nNewXPos ); |
1040 |
virtual void MoveGlyph( int nStart, long nNewXPos ); |
Lines 1075-1080
Link Here
|
1075 |
|
1076 |
|
1076 |
// font specific info |
1077 |
// font specific info |
1077 |
int mnMinKashidaWidth; // minimal Kashida width allowed by font |
1078 |
int mnMinKashidaWidth; // minimal Kashida width allowed by font |
|
|
1079 |
|
1080 |
// kashida stuff |
1081 |
void KashidaItemFix( int nMinGlyphPos, int nEndGlyphPos ); |
1082 |
|
1083 |
bool KashidaWordFix ( int nMinGlyphPos, int nEndGlyphPos, int* pnCurrentPos ); |
1084 |
|
1085 |
|
1078 |
}; |
1086 |
}; |
1079 |
|
1087 |
|
1080 |
// ----------------------------------------------------------------------- |
1088 |
// ----------------------------------------------------------------------- |
Lines 2368-2433
Link Here
|
2368 |
{ |
2376 |
{ |
2369 |
for( i = nMinGlyphPos; i < nEndGlyphPos; ++i ) |
2377 |
for( i = nMinGlyphPos; i < nEndGlyphPos; ++i ) |
2370 |
nXOffset += mpJustifications[ i ]; |
2378 |
nXOffset += mpJustifications[ i ]; |
2371 |
|
2379 |
|
2372 |
// TODO: for kashida justification |
2380 |
if ( bHasKashida ) |
2373 |
// check the widths which are added to mpJustification |
2381 |
KashidaItemFix ( nMinGlyphPos, nEndGlyphPos ); |
2374 |
// if added width is smaller than iKashidaWidth returned by |
|
|
2375 |
// ScriptGetFontProperties, do something (either enlarge to |
2376 |
// iKashidaWidth, or reduce to original width). |
2377 |
// Need to think of a way to compensate the change in overall |
2378 |
// width. |
2379 |
|
2380 |
if ( bHasKashida && mnMinKashidaWidth ) |
2381 |
{ |
2382 |
int nSpaceAdded; |
2383 |
for ( i = nMinGlyphPos; i < nEndGlyphPos; ++i ) |
2384 |
{ |
2385 |
nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ]; |
2386 |
if ( nSpaceAdded && ((1U << mpVisualAttrs[i].uJustification) & 0xFF89 )) |
2387 |
{ |
2388 |
if ( i > nMinGlyphPos && ! mpGlyphAdvances [ i - 1 ] && nSpaceAdded >= mnMinKashidaWidth) |
2389 |
{ |
2390 |
// vowel, we do it like ScriptJustify does |
2391 |
// this works great !!! |
2392 |
mpJustifications [ i ] = mpGlyphAdvances [ i ]; |
2393 |
mpJustifications [ i - 1 ] += nSpaceAdded; |
2394 |
} |
2395 |
|
2396 |
if ( nSpaceAdded < mnMinKashidaWidth ) |
2397 |
{ |
2398 |
mpJustifications[ i ] = mpGlyphAdvances[ i ]; // overriding; |
2399 |
/*for ( int j = i; j >= nMinGlyphPos; --j ) |
2400 |
{ |
2401 |
if ( mpVisualAttrs[ j ].uJustification == SCRIPT_JUSTIFY_ARABIC_BLANK ) |
2402 |
{ |
2403 |
mpJustifications [ j ] += nSpaceAdded; // padding a blank instead |
2404 |
nSpaceAdded = 0; |
2405 |
break; |
2406 |
} |
2407 |
}*/ |
2408 |
|
2409 |
// no blank found |
2410 |
// try the other side |
2411 |
for ( int j = i; j < nEndGlyphPos; ++j ) |
2412 |
{ |
2413 |
if ( mpVisualAttrs[ j ].uJustification == SCRIPT_JUSTIFY_ARABIC_BLANK ) |
2414 |
{ |
2415 |
mpJustifications [ j ] += nSpaceAdded; // padding a blank instead |
2416 |
nSpaceAdded = 0; |
2417 |
break; |
2418 |
} |
2419 |
} |
2420 |
|
2421 |
if ( nSpaceAdded ) |
2422 |
{ |
2423 |
// no blank found |
2424 |
// right align |
2425 |
// rVisualItem.mnXOffset += nSpaceAdded; |
2426 |
} |
2427 |
} |
2428 |
} |
2429 |
} |
2430 |
} |
2431 |
} |
2382 |
} |
2432 |
|
2383 |
|
2433 |
// right align the justification-adjusted glyphs in their cells for RTL-items |
2384 |
// right align the justification-adjusted glyphs in their cells for RTL-items |
Lines 2447-2452
Link Here
|
2447 |
} |
2398 |
} |
2448 |
|
2399 |
|
2449 |
// ----------------------------------------------------------------------- |
2400 |
// ----------------------------------------------------------------------- |
|
|
2401 |
void UniscribeLayout::KashidaItemFix( int nMinGlyphPos, int nEndGlyphPos ) |
2402 |
{ |
2403 |
// check for vowels |
2404 |
for ( int i = nMinGlyphPos; i < nEndGlyphPos; ++i ) |
2405 |
{ |
2406 |
if ( i > nMinGlyphPos && !mpGlyphAdvances[ i-1 ] && (1U << mpVisualAttrs[i].uJustification) & 0xFF89 ) |
2407 |
{ |
2408 |
// vowel, we do it like ScriptJustify does |
2409 |
// the vowel gets the extra width |
2410 |
long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ]; |
2411 |
mpJustifications [ i ] = mpGlyphAdvances [ i ]; |
2412 |
mpJustifications [ i - 1 ] += nSpaceAdded; |
2413 |
} |
2414 |
} |
2415 |
|
2416 |
int i = nMinGlyphPos; |
2417 |
while ( i < nEndGlyphPos ) |
2418 |
{ |
2419 |
KashidaWordFix ( nMinGlyphPos, nEndGlyphPos, &i ); |
2420 |
} |
2421 |
} |
2422 |
|
2423 |
bool UniscribeLayout::KashidaWordFix ( int nMinGlyphPos, int nEndGlyphPos, int* pnCurrentPos ) |
2424 |
{ |
2425 |
// doing pixel work within a word. |
2426 |
// sometimes we have extra pixels and sometimes we miss some pixels to get to mnMinKashidaWidth |
2427 |
|
2428 |
int nMinPos = *pnCurrentPos; |
2429 |
int nMaxPos = *pnCurrentPos; |
2430 |
for ( int i = nMaxPos; i < nEndGlyphPos; ++i ) |
2431 |
{ |
2432 |
if ( mpVisualAttrs [ i ].uJustification >= SCRIPT_JUSTIFY_ARABIC_BLANK && |
2433 |
mpVisualAttrs [ i ].uJustification < SCRIPT_JUSTIFY_ARABIC_NORMAL ) |
2434 |
break; |
2435 |
nMaxPos = i; |
2436 |
} |
2437 |
*pnCurrentPos = nMaxPos + 1; |
2438 |
if ( nMinPos == nMaxPos ) |
2439 |
return false; |
2440 |
|
2441 |
long nMaxAdded = 0; |
2442 |
int nKashPos = -1; |
2443 |
for( int i = nMaxPos; i >= nMinPos; --i ) |
2444 |
{ |
2445 |
long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ]; |
2446 |
if( nSpaceAdded > nMaxAdded ) |
2447 |
{ |
2448 |
nKashPos = i; |
2449 |
nMaxAdded = nSpaceAdded; |
2450 |
} |
2451 |
} |
2452 |
if ( nMaxAdded <= 0 ) |
2453 |
return false; |
2454 |
if( nMaxAdded < mnMinKashidaWidth / 2 ) |
2455 |
// too small for a kashida |
2456 |
nKashPos = -1; |
2457 |
|
2458 |
//long nTooMuch = 0; |
2459 |
if ( nKashPos != -1 ) |
2460 |
for( int i = nMinPos; i <= nMaxPos; ++i ) |
2461 |
{ |
2462 |
if( i==nKashPos ) continue; |
2463 |
// everything else should not have extra spacing |
2464 |
long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ]; |
2465 |
if ( nSpaceAdded > 0 ) |
2466 |
{ |
2467 |
mpJustifications[ i ] -= nSpaceAdded; |
2468 |
mpJustifications[ nKashPos ] += nSpaceAdded; |
2469 |
} |
2470 |
} |
2471 |
|
2472 |
/* if( nTooMuch > 0 ) |
2473 |
{ |
2474 |
if ( nMinPos > nMinGlyphPos && nMaxPos < nEndGlyphPos - 1) |
2475 |
{ |
2476 |
long nHalfSpace = nTooMuch / 2; |
2477 |
mpJustifications [ nMinPos - 1 ] += nHalfSpace; |
2478 |
mpJustifications [ nMaxPos + 1 ] += nTooMuch - nHalfSpace; |
2479 |
} |
2480 |
else if ( nMinPos > nMinGlyphPos ) |
2481 |
{ |
2482 |
mpJustifications [ nMinPos - 1 ] += nTooMuch; |
2483 |
} |
2484 |
else if ( nMaxPos < nEndGlyphPos - 1 ) |
2485 |
{ |
2486 |
mpJustifications [ nMaxPos + 1 ] += nTooMuch; |
2487 |
} |
2488 |
else return false; |
2489 |
}*/ |
2490 |
|
2491 |
// check if we fulfill minimal kashida width |
2492 |
if( nKashPos != -1 ) |
2493 |
{ |
2494 |
long nSpaceAdded = mpJustifications[ nKashPos ] - mpGlyphAdvances[ nKashPos ]; |
2495 |
if( nSpaceAdded < mnMinKashidaWidth ) |
2496 |
{ |
2497 |
// ugly: steal some pixels |
2498 |
long nSteal = 1; |
2499 |
if ( nMaxPos - nMinPos > 0 && ((mnMinKashidaWidth - nSpaceAdded) > ( nMaxPos - nMinPos ))) |
2500 |
nSteal = (mnMinKashidaWidth - nSpaceAdded) / ( nMaxPos - nMinPos ); |
2501 |
for ( int i = nMinPos; i <= nMaxPos; ++i ) |
2502 |
{ |
2503 |
if ( i == nKashPos ) continue; |
2504 |
nSteal = Min ( mnMinKashidaWidth - nSpaceAdded, nSteal ); |
2505 |
if ( nSteal > 0 ) |
2506 |
{ |
2507 |
mpJustifications [ i ] -= nSteal; |
2508 |
mpJustifications [ nKashPos ] += nSteal; |
2509 |
nSpaceAdded += nSteal; |
2510 |
} |
2511 |
if ( nSpaceAdded >= mnMinKashidaWidth ) |
2512 |
return true; |
2513 |
} |
2514 |
} |
2515 |
long nSpaceMissing = mnMinKashidaWidth - nSpaceAdded; |
2516 |
|
2517 |
// blank padding |
2518 |
if ( nSpaceMissing > 0 ) |
2519 |
{ |
2520 |
if ( nMinPos > nMinGlyphPos && nMaxPos < nEndGlyphPos - 1) |
2521 |
{ |
2522 |
mpJustifications [ nKashPos ] += nSpaceMissing; |
2523 |
long nHalfSpace = nSpaceMissing / 2; |
2524 |
mpJustifications [ nMinPos - 1 ] -= nHalfSpace; |
2525 |
mpJustifications [ nMaxPos + 1 ] -= nSpaceMissing - nHalfSpace; |
2526 |
} |
2527 |
else if ( nMinPos > nMinGlyphPos ) |
2528 |
{ |
2529 |
mpJustifications [ nMinPos - 1 ] -= nSpaceMissing; |
2530 |
mpJustifications [ nKashPos ] += nSpaceMissing; |
2531 |
} |
2532 |
else if ( nMaxPos < nEndGlyphPos - 1 ) |
2533 |
{ |
2534 |
mpJustifications [ nKashPos ] += nSpaceMissing; |
2535 |
mpJustifications [ nMaxPos + 1 ] -= nSpaceMissing; |
2536 |
} |
2537 |
else return false; |
2538 |
} |
2539 |
} |
2540 |
return true; |
2541 |
} |
2542 |
|
2543 |
// ----------------------------------------------------------------------- |
2450 |
|
2544 |
|
2451 |
void UniscribeLayout::Justify( long nNewWidth ) |
2545 |
void UniscribeLayout::Justify( long nNewWidth ) |
2452 |
{ |
2546 |
{ |
Lines 2496-2501
Link Here
|
2496 |
} |
2590 |
} |
2497 |
} |
2591 |
} |
2498 |
|
2592 |
|
|
|
2593 |
bool UniscribeLayout::IsKashidaPosValid ( int nCharPos ) const |
2594 |
{ |
2595 |
// we have to find the visual item first since the mpLogClusters[] |
2596 |
// needed to find the cluster start is relative to to the visual item |
2597 |
int nMinGlyphIndex = -1; |
2598 |
for( int nItem = 0; nItem < mnItemCount; ++nItem ) |
2599 |
{ |
2600 |
const VisualItem& rVisualItem = mpVisualItems[ nItem ]; |
2601 |
if( (nCharPos >= rVisualItem.mnMinCharPos) |
2602 |
&& (nCharPos < rVisualItem.mnEndCharPos) ) |
2603 |
{ |
2604 |
if ( nCharPos < rVisualItem.mnEndCharPos - 1 ) |
2605 |
// our nCharPos mustn't be the last char in the |
2606 |
// item |
2607 |
nMinGlyphIndex = rVisualItem.mnMinGlyphPos; |
2608 |
break; |
2609 |
} |
2610 |
} |
2611 |
// Invalid char pos or leftmost glyph in visual item |
2612 |
if ( nMinGlyphIndex == -1 || !mpLogClusters[ nCharPos ] ) |
2613 |
return false; |
2614 |
|
2615 |
// This test didn't give the expected results |
2616 |
/* if( mpLogClusters[ nCharPos+1 ] == mpLogClusters[ nCharPos ]) |
2617 |
// two chars, one glyph |
2618 |
return false;*/ |
2619 |
|
2620 |
|
2621 |
const int nGlyphPos = mpLogClusters[ nCharPos ] + nMinGlyphIndex; |
2622 |
// justification is only allowed if the glyph to the left has not SCRIPT_JUSTIFY_NONE |
2623 |
// and not SCRIPT_JUSTIFY_ARABIC_BLANK |
2624 |
// special case: glyph to the left is vowel (no advance width) |
2625 |
if ( mpVisualAttrs[ nGlyphPos-1 ].uJustification == SCRIPT_JUSTIFY_ARABIC_BLANK |
2626 |
|| ( mpVisualAttrs[ nGlyphPos-1 ].uJustification == SCRIPT_JUSTIFY_NONE |
2627 |
&& mpGlyphAdvances [ nGlyphPos-1 ] )) |
2628 |
return false; |
2629 |
return true; |
2630 |
} |
2631 |
|
2499 |
#endif // USE_UNISCRIBE |
2632 |
#endif // USE_UNISCRIBE |
2500 |
|
2633 |
|
2501 |
// ======================================================================= |
2634 |
// ======================================================================= |