{******************************************************************************} {* *} {* Copyright (c) Microsoft Corporation. All rights reserved. *} {* *} {* File: usp10.h *} {* Content: USP - Unicode Complex Script processor *} {* *} {* Delphi / FreePascal adaptation by Alexey Barkovoy (clootie@clootie.ru) *} (* *) {* The original version from Alexey Barkovoy can be downloaded from: *} {* http://clootie.ru *} (* *) (* Dynamic linking logic (similar to what the JCL does) by Maël Hörz. *) (* *) (* Latest version can be downloaded from http://mh-nexus.de/unisynedit.htm *) (* or checked out from the Unicode branch of SynEdit CVS. *) (* *) {******************************************************************************} { } { The contents of this file are used with permission, subject to the Mozilla } { Public License Version 1.1 (the "License"); you may not use this file except } { in compliance with the License. You may obtain a copy of the License at } { http://www.mozilla.org/MPL/MPL-1.1.html } { } { Software distributed under the License is distributed on an "AS IS" basis, } { WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for } { the specific language governing rights and limitations under the License. } { } { Alternatively, the contents of this file may be used under the terms of the } { GNU Lesser General Public License (the "LGPL License"), in which case the } { provisions of the LGPL License are applicable instead of those above. } { If you wish to allow use of your version of this file only under the terms } { of the LGPL License and not to allow others to use your version of this file } { under the MPL, indicate your decision by deleting the provisions above and } { replace them with the notice and other provisions required by the LGPL } { License. If you do not delete the provisions above, a recipient may use } { your version of this file under either the MPL or the LGPL License. } { } { For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html } { } {******************************************************************************} // $Id: SynUsp10.pas,v 1.1.2.2 2008/09/17 13:59:12 maelh Exp $ {$IFDEF FPC} {$mode objfpc} {$ENDIF} // necessary for dynamic linking {$STACKFRAMES ON} {$WARNINGS OFF} unit SynUsp10; interface uses Windows; const ///// Uniscribe build number USPBUILD = 0400; ///// USP - Unicode Complex Script processor // // Copyright (c) Microsoft Corporation. All rights reserved. ///// SCRIPT // // The SCRIPT enum is an opaque type used internally to identify // which shaping engine functions are used to process a given run. // // SCRIPT_UNDEFINED = 0; // //p SCRIPT_UNDEFINED: This is the only public script ordinal. May be // forced into the eScript field of a SCRIPT_ANALYSIS to disable shaping. // SCRIPT_UNDEFINED is supported by all fonts - ScriptShape will display // whatever glyph is defined in the font CMAP table, or, if none, the // missing glyph. ///// USP Status Codes // USP_E_SCRIPT_NOT_IN_FONT = DWord((SEVERITY_ERROR shl 31) or (FACILITY_ITF shl 16)) or $200; // MAKE_HRESULT(SEVERITY_ERROR,FACILITY_ITF,0x200) // Script doesn't exist in font ///// SCRIPT_CACHE // // Many script APIs take a combination of HDC and SCRIPT_CACHE parameter. // // A SCRIPT_CACHE is an opaque pointer to a Uniscribe font metric cache // structure. type SCRIPT_CACHE = Pointer; {$EXTERNALSYM SCRIPT_CACHE} TScriptCache = SCRIPT_CACHE; PScriptCache = ^TScriptCache; // The client must allocate and retain one SCRIPT_CACHE variable for each // character style used. It must be initialised by the client to NULL. // // APIs are passed an HDC and the address of a SCRIPT_CACHE variable. // Uniscribe will first attempt to access font data via the SCRIPT_CACHE // and will only inspect the HDC if the required data is not already // cached. // // The HDC may be passed as NULL. If data required by Uniscribe is // already cached, the HDC won't be accessed and operation continues // normally. // // If the HDC is passed as NULL, and Uniscribe needs to access it for // any reason, Uniscribe will return E_PENDING. // // E_PENDING is returned quickly, allowing the client to avoid time // consuming SelectObject calls. The following example applies to all // APIs that take a SCRIPT_CACHE and an optional HDC. // //c hr = ScriptShape(NULL, &sc, ..); //c if (hr == E_PENDING) { //c ... select font into hdc ... //c hr = ScriptShape(hdc, &sc, ...); //c } ///// ScriptFreeCache // // The client may free a SCRIPT_CACHE at any time. Uniscribe maintains // reference counts in it's font and shaper caches, and frees font data // only when all sizes of the font are free, and shaper data only when // all fonts it supports are freed. // // The client should free the SCRIPT_CACHE for a style when it discards // that style. // // ScriptFreeCache always sets it's parameter to NULL to help avoid // mis-referencing. function ScriptFreeCache( psc: PScriptCache //InOut Cache handle ): HRESULT; stdcall; type ///// SCRIPT_CONTROL // // The SCRIPT_CONTROL structure provides itemization control flags to the // ScriptItemize function. // // TScriptControlFlag = ( scContextDigits, // Means use previous script instead of uDefaultLanguage // The following flags provide legacy support for GetCharacterPlacement features scInvertPreBoundDir, // Reading order of virtual item immediately prior to string scInvertPostBoundDir, // Reading order of virtual item immediately following string scLinkStringBefore, // Equivalent to presence of ZWJ before string scLinkStringAfter, // Equivalent to presence of ZWJ after string scNeutralOverride, // Causes all neutrals to be strong in the current embedding direction scNumericOverride, // Causes all numerals to be strong in the current embedding direction scLegacyBidiClass // Causes plus and minus to be reated as neutrals, slash as a common separator ); TScriptControlFlags = set of TScriptControlFlag; PScriptControl = ^TScriptControl; tag_SCRIPT_CONTROL = packed record uDefaultLanguage: Word; // For NADS, also default for context fFlags: TScriptControlFlags; fReserved: Byte; end; (* uDefaultLanguage: DWORD {:16}; // For NADS, also default for context fContextDigits: DWORD {:1}; // Means use previous script instead of uDefaultLanguage // The following flags provide legacy support for GetCharacterPlacement features fInvertPreBoundDir: DWORD {:1}; // Reading order of virtual item immediately prior to string fInvertPostBoundDir: DWORD {:1}; // Reading order of virtual item immediately following string fLinkStringBefore: DWORD {:1}; // Equivalent to presence of ZWJ before string fLinkStringAfter: DWORD {:1}; // Equivalent to presence of ZWJ after string fNeutralOverride: DWORD {:1}; // Causes all neutrals to be strong in the current embedding direction fNumericOverride: DWORD {:1}; // Causes all numerals to be strong in the current embedding direction fLegacyBidiClass: DWORD {:1}; // Causes plus and minus to be reated as neutrals, slash as a common separator fReserved: DWORD {:8}; end; *) {$EXTERNALSYM tag_SCRIPT_CONTROL} SCRIPT_CONTROL = tag_SCRIPT_CONTROL; {$EXTERNALSYM SCRIPT_CONTROL} TScriptControl = tag_SCRIPT_CONTROL; // // //p uDefaultLanguage: Language to use when Unicode values are ambiguous. // Used by numeric processing to select digit shape when // ssDigitSubstitute (see SCRIPT_STATE) is in force. // //p scContextDigits: Specifies that national digits are chosen according to // the nearest previous strong text, rather than using // uDefaultLanguage. // //p scInvertPreBoundDir: By default text at the start of the string is // laid out as if it follows strong text of the same direction // as the base embedding level. Set scInvertPreBoundDir to change // the initial context to the opposite of the base embedding // level. This flag is for GetCharacterPlacement legacy support. // //p scInvertPostBoundDir: By default text at the end of the string is // laid out as if it preceeds strong text of the same direction // as the base embedding level. Set scInvertPostBoundDir to change // the final context to the opposite of the base embedding // level. This flag is for GetCharacterPlacement legacy support. // //p scLinkStringBefore: Causes the first character of the string to be // shaped as if were joined to a previous character. // //p scLinkStringAfter: Causes the last character of the string to be // shaped as if were joined to a following character. // //p scNeutralOverride: Causes all neutral characters in the string to be // treated as if they were strong characters of their enclosing // embedding level. This effectively locks neutrals in place, // reordering occuring only between neutrals. // //p scNumericOverride: Causes all numeric characters in the string to be // treated as if they were strong characters of their enclosing // embedding level. This effectively locks numerics in place, // reordering occuring only between numerics. // //p fReserved: Reserved. Always initialise to 0. ///// SCRIPT_STATE // // The SCRIPT_STATE structure is used both to initialise the unicode // algorithm state as an input parameter to ScriptItemize, and is also // a component of each item analysis returned by ScriptItemize. // // TScriptStateFlag = ( uBidiLevel_reserved1, uBidiLevel_r2, uBidiLevel_r3, uBidiLevel_r4, uBidiLevel_r5, ssOverrideDirection, // Set when in LRO/RLO embedding ssInhibitSymSwap, // Set by U+206A (ISS), cleared by U+206B (ASS) ssCharShape, // Set by U+206D (AAFS), cleared by U+206C (IAFS) ssDigitSubstitute, // Set by U+206E (NADS), cleared by U+206F (NODS) ssInhibitLigate, // Equiv !GCP_Ligate, no Unicode control chars yet ssDisplayZWG, // Equiv GCP_DisplayZWG, no Unicode control characters yet ssArabicNumContext, // For EN->AN Unicode rule ssGcpClusters // For Generating Backward Compatible GCP Clusters (legacy Apps) ); TScriptStateFlags = set of TScriptStateFlag; PScriptState = ^TScriptState; tag_SCRIPT_STATE = packed record case Byte of 0: (uBidiLevel: Byte) {:5}; // Unicode Bidi algorithm embedding level (0-16) 1: (fFlags: TScriptStateFlags) end; (* uBidiLevel: Word {:5}; // Unicode Bidi algorithm embedding level (0-16) fOverrideDirection: Word {:1}; // Set when in LRO/RLO embedding fInhibitSymSwap: Word {:1}; // Set by U+206A (ISS), cleared by U+206B (ASS) fCharShape: Word {:1}; // Set by U+206D (AAFS), cleared by U+206C (IAFS) fDigitSubstitute: Word {:1}; // Set by U+206E (NADS), cleared by U+206F (NODS) fInhibitLigate: Word {:1}; // Equiv !GCP_Ligate, no Unicode control chars yet fDisplayZWG: Word {:1}; // Equiv GCP_DisplayZWG, no Unicode control characters yet fArabicNumContext: Word {:1}; // For EN->AN Unicode rule fcpClusters: Word {:1}; // For Generating Backward Compatible GCP Clusters (legacy Apps) fReserved: Word {:1}; fEngineReserved: Word {:2}; // For use by shaping engine end; *) {$EXTERNALSYM tag_SCRIPT_STATE} SCRIPT_STATE = tag_SCRIPT_STATE; {$EXTERNALSYM SCRIPT_STATE} TScriptState = tag_SCRIPT_STATE; const MASK_uBidiLevel = $1F; // Mask to apply to TScriptState.uBidiLevel type // // //p uBidiLevel: The embedding level associated with all characters in this // run according to the Unicode bidi algorithm. When passed to // ScriptItemize, should be initialised to 0 for an LTR base // embedding level, or 1 for RTL. // //p ssOverrideDirection: TRUE if this level is an override level (LRO/RLO). // In an override level, characters are layed out purely // left to right, or purely right to left. No reordering of digits // or strong characters of opposing direction takes place. // Note that this initial value is reset by LRE, RLE, LRO or // RLO codes in the string. // //p ssInhibitSymSwap: TRUE if the shaping engine is to bypass mirroring of // Unicode Mirrored glyphs such as brackets. Set by Unicode // character ISS, cleared by ASS. // //p ssCharShape: TRUE if character codes in the Arabic Presentation Forms // areas of Unicode should be shaped. (Not implemented). // //p ssDigitSubstitute: TRUE if character codes U+0030 through U+0039 // (European digits) are to be substituted by national digits. // Set by Unicode NADS, Cleared by NODS. // //p ssInhibitLigate: TRUE if ligatures are not to be used in the shaping // of Arabic or Hebrew characters. // //p ssDisplayZWG: TRUE if control characters are to be shaped as // representational glyphs. (Normally, control characters are // shaped to the blank glyph and given a width of zero). // //p ssArabicNumContext: TRUE indicates prior strong characters were Arabic // for the purposes of rule P0 on page 3-19 of 'The Unicode // Standard, version 2.0'. Should normally be set TRUE before // itemizing an RTL paragraph in an Arabic language, FALSE // otherwise. // //p ssGcpClusters: For GetCharaterPlacement legacy support only. // Initialise to TRUE to request ScriptShape to generate // the LogClust array the same way as GetCharacterPlacement // does in Arabic and Hebrew Windows95. Affects only Arabic // and Hebrew items. // //p fReserved: Reserved. Always initialise to 0. // //p fEngineReserved: Reserved. Always initialise to 0. ///// SCRIPT_ANALYSIS // // Each analysed item is described by a SCRIPT_ANALYSIS structure. // It also includes a copy of the Unicode algorithm state (SCRIPT_STATE). // // TScriptAnalysis_enum = ( eScript_r1, eScript_r2, eScript_r3, eScript_r4, eScript_r5, // first 10 bits eScript_r6, eScript_r7, eScript_r8, eScript_r9, eScript_r10, // are reserved fRTL, // Rendering direction fLayoutRTL, // Set for GCP classes ARABIC/HEBREW and LOCALNUMBER fLinkBefore, // Implies there was a ZWJ before this item fLinkAfter, // Implies there is a ZWJ following this item. fLogicalOrder, // Set by client as input to ScriptShape/Place fNoGlyphIndex // Generated by ScriptShape/Place - this item does not use glyph indices ); TScriptAnalysis_set = set of TScriptAnalysis_enum; PScriptAnalysis = ^TScriptAnalysis; tag_SCRIPT_ANALYSIS = packed record case Byte of 0: (eScript: Word) {:10}; // Shaping engine 1: (fFlags: TScriptAnalysis_set; s: TScriptState) end; (* eScript: Word {:10}; // Shaping engine fRTL: Word {:1}; // Rendering direction fLayoutRTL: Word {:1}; // Set for GCP classes ARABIC/HEBREW and LOCALNUMBER fLinkBefore: Word {:1}; // Implies there was a ZWJ before this item fLinkAfter: Word {:1}; // Implies there is a ZWJ following this item. fLogicalOrder: Word {:1}; // Set by client as input to ScriptShape/Place fNoGlyphIndex: Word {:1}; // Generated by ScriptShape/Place - this item does not use glyph indices s: TScriptState; end; *) {$EXTERNALSYM tag_SCRIPT_ANALYSIS} SCRIPT_ANALYSIS = tag_SCRIPT_ANALYSIS; {$EXTERNALSYM SCRIPT_ANALYSIS} TScriptAnalysis = tag_SCRIPT_ANALYSIS; const MASK_eScript = $3FF; // Mask to apply to TScriptAnalysis.eScript type // // //p eScript: Opaque value identifying which engine Uniscribe will use to // Shape, Place and TextOut this item. The value of eScript is // undefined, and will change in future releases, but attributes // of eScript may be obtained by calling ScriptGetProperties. // //p fRTL: Rendering direction. Normally identical to the parity of the // Unicode embedding level, but may differ if overridden by // GetCharacterPlacement legacy support. // //p fLayoutRTL: Logical direction - whether conceptually part of a // left-to-right sequenece or a right-to-left sequence. Although // this is usually the same as fRTL, for a number in a // right-to-left run, fRTL is False (because digits are always // displayed LTR), but fLayoutRTL is True (because the number is // read as part of the right-to-left sequence). // //p fLinkBefore: If set, the shaping engine will shape the first character // of this item as if it were joining with a previous character. // Set by ScriptItemize, may be overriden before calling ScriptShape. // //p fLinkAfter: If set, the shaping engine will shape the last character // of this item as if it were joining with a subsequient character. // Set by ScriptItemize, may be overriden before calling ScriptShape. // //p fLogicalOrder: If set, the shaping engine will generate all glyph // related arrays in logical order. By default glyph related // arrays are in visual order, the first array entry corresponding // to the leftmost glyph. // Set to FALSE by ScriptItemize, may be overriden before calling // ScriptShape. // //p fNoGlyphIndex: May be set TRUE on input to ScriptShape to disable use // of glyphs for this item. Additionally, ScriptShape will set it // TRUE for hdcs containing symbolic, unrecognised and device fonts. // Disabling glyphing disables complex script shaping. When set, // shaping and placing for this item is implemented directly by // calls to GetTextExtentExPoint and ExtTextOut. ///// SCRIPT_ITEM // // The SCRIPT_ITEM structure includes a SCRIPT_ANALYSIS with the string // ofset of the first character of the item. // // PScriptItem = ^TScriptItem; tag_SCRIPT_ITEM = record iCharPos: Integer; // Logical offset to first character in this item a: TScriptAnalysis; end; {$EXTERNALSYM tag_SCRIPT_ITEM} SCRIPT_ITEM = tag_SCRIPT_ITEM; {$EXTERNALSYM SCRIPT_ITEM} TScriptItem = SCRIPT_ITEM; // // //p iCharPos: Offset from beginning of itemised string to first character // of this item, counted in Unicode codepoints (i.e. words). // //p a: Script analysis structure containing analysis specific to this // item, to be passed to ScriptShape, ScriptPlace etc. ///// ScriptItemize - break text into items // // Breaks a run of unicode into individually shapeable items. // Items are delimited by // // o Change of shaping engine // o Change of direction // // The client may create multiple runs from each item returned by // ScriptItemize, but should not combine multiple items into a single run. // // Later the client will call ScriptShape for each run (when measuring or // rendering), and must pass the SCRIPT_ANALYSIS that ScriptItemize // returned. function ScriptItemize( const pwcInChars: PWideChar; // In Unicode string to be itemized cInChars: Integer; // In Codepoint count to itemize cMaxItems: Integer; // In Max length of itemization array const psControl: PScriptControl; // In Analysis control (optional) const psState: PScriptState; // In Initial bidi algorithm state (optional) pItems: PScriptItem; // Out Array to receive itemization pcItems: PInteger // Out Count of items processed (optional) ): HRESULT; stdcall; {$EXTERNALSYM ScriptItemize} ///// // // // Returns E_INVALIDARG if pwcInChars == NULL or cInChars == 0 // or pItems == NULL or cMaxItems < 2. // // Returns E_OUTOFMEMORY if the output buffer length (cMaxItems) is // insufficient. Note that in this case, as in all error cases, no // items have been fully processed so no part of the output array // contains defined values. // // If psControl and psState are NULL on entry, ScriptItemize // breaks the unicode string purely by character code. If they are all // non-null, it performs a full Unicode bidi analysis. // // ScriptItemize always adds a terminal item to the item analysis array // (pItems) such that the length of an item at pItem is always available as: // //c pItem[1].iCharPos - pItem[0].iCharPos // // For this reason, it is invalid to call ScriptItemize with a buffer // of less than two SCRIPT_ANALYSIS items. // // To perform a correct Unicode Bidi analysis, the SCRIPT_STATE should // be initialised according to the paragraph reading order at paragraph // start, and ScriptItemize should be passed the whole paragraph. // // fRTL and fNumeric together provide the same classification as // the lpClass output from GetCharacterPlacement. // // European digits U+0030 through U+0039 may be rendered as national // digits as follows: // //t ssDigitSubstitute | scContextDigits | Digit shapes displayed for Unicode U+0030 through U+0039 //t ---------------- | -------------- | ------------------------------------ //t False | Any | Western (European / American) digits //t True | False | As specified in SCRIPT_CONTROL.uDefaultLanguage //t True | True | As prior strong text, defaulting to SCRIPT_CONTROL.uDefaultLanguage // // // For scContextDigits, any Western digits (U+0030 - U+0039) encountered // before the first strongly directed character are substituted by the // traditional digits of the SCRIPT_CONTROL.uDefaultLanguage when that // language is written in the same direction as SCRIPT_STATE.uBidiLevel. // // Thus, in a right-to-left string, if SCRIPT_CONTROL.uDefaultLanguage is // 1 (LANG_ARABIC), then leading Western digits will be substituted by // traditional Arabic digits. // // However, also in a right-to-left string, if SCRIPT_CONTROL.uDefaultLanguage // is 0x1e (LANG_THAI), then no substitution occurs on leading Western // digits because the Thai language is written left-to-right. // // Following strongly directed characters, digits are substituted // by the traditional digits associated with the closest prior strongly // directed character. // // The left-to-right mark (LRM) and right-to-left mark (RLM) are strong // characters whose language depends on the SCRIPT_CONTROL.uDefaultLangauge. // // If SCRIPT_CONTROL.uDefaultLangauge is a left-to-right langauge, then // LRM causes subsequent Western digits to be substituted by the // traditional digits associated with that language, while Western // digits following RLM are not substituted. // // Conversly, if SCRIPT_CONTROL.uDefaultLangauge is a right-to-left // langauge, then Western digits following LRM are not substituted, while // Western digits following RLM are substituted by the traditional digits // associated with that language. // // // // Effect of Unicode control characters on SCRIPT_STATE: // //t SCRIPT_STATE flag | Set by | Cleared by //t ----------------- | ------ ---------- //t ssDigitSubstitute | NADS | NODS //t ssInhibitSymSwap | ISS | ASS //t ssCharShape | AAFS | IAFS // // SCRIPT_STATE.ssArabicNumContext controls the Unicode EN->AN rule. // It should normally be initialised to TRUE // before itemizing an RTL paragraph in an Arabic language, FALSE // otherwise. ///// ScriptLayout // // The ScriptLayout function converts an array of run embedding levels to // a map of visual to logical position, and/or logical to visual position. // // pbLevel must contain the embedding levels for all runs on the line, // ordered logically. // // On output, piVisualToLogical[0] is the logical index of the run to // display at the far left. Subsequent entries should be displayed // progressing from left to right. // // piLogicalToVisual[0] is the relative visual position where the first // logical run should be displayed - the leftmost display position being zero. // // The caller may request either piLogicalToVisual or piVisualToLogical // or both. // // Note: No other input is required since the embedding levels give all // necessary information for layout. function ScriptLayout( cRuns: Integer; // In Number of runs to process const pbLevel: PByte; // In Array of run embedding levels piVisualToLogical: PInteger; // Out List of run indices in visual order piLogicalToVisual: PInteger // Out List of visual run positions ): HRESULT; stdcall; {$EXTERNALSYM ScriptLayout} type ///// SCRIPT_JUSTIFY // // The script justification enumeration provides the client with the // glyph characteristic information it needs to implement justification. PScriptJustify = ^TScriptJustify; tag_SCRIPT_JUSTIFY = ( SCRIPT_JUSTIFY_NONE {= 0}, // Justification can't be applied at this glyph SCRIPT_JUSTIFY_ARABIC_BLANK {= 1}, // This glyph represents a blank in an Arabic run SCRIPT_JUSTIFY_CHARACTER {= 2}, // Inter-character justification point follows this glyph SCRIPT_JUSTIFY_RESERVED1 {= 3}, // Reserved #1 SCRIPT_JUSTIFY_BLANK {= 4}, // This glyph represents a blank outside an Arabic run SCRIPT_JUSTIFY_RESERVED2 {= 5}, // Reserved #2 SCRIPT_JUSTIFY_RESERVED3 {= 6}, // Reserved #3 SCRIPT_JUSTIFY_ARABIC_NORMAL {= 7}, // Normal Middle-Of-Word glyph that connects to the right (begin) SCRIPT_JUSTIFY_ARABIC_KASHIDA {= 8}, // Kashida(U+640) in middle of word SCRIPT_JUSTIFY_ARABIC_ALEF {= 9}, // Final form of Alef-like (U+627, U+625, U+623, U+632) SCRIPT_JUSTIFY_ARABIC_HA {= 10}, // Final form of Ha (U+647) SCRIPT_JUSTIFY_ARABIC_RA {= 11}, // Final form of Ra (U+631) SCRIPT_JUSTIFY_ARABIC_BA {= 12}, // Middle-Of-Word form of Ba (U+628) SCRIPT_JUSTIFY_ARABIC_BARA {= 13}, // Ligature of alike (U+628,U+631) SCRIPT_JUSTIFY_ARABIC_SEEN {= 14}, // Highest priority: Initial shape of Seen(U+633) (end) SCRIPT_JUSTIFY_RESERVED4 {= 15} // Reserved #4 ); SCRIPT_JUSTIFY = tag_SCRIPT_JUSTIFY; {$EXTERNALSYM SCRIPT_JUSTIFY} TScriptJustify = SCRIPT_JUSTIFY; ///// SCRIPT_VISATTR // // The visual (glyph) attribute buffer generated by ScriptShape // identifies clusters and justification points: TScriptVisAttr_enum = ( uJustification_r1, uJustification_r2, uJustification_r3, uJustification_r4, fClusterStart, {:1} // First glyph of representation of cluster fDiacritic, {:1} // Diacritic fZeroWidth, {:1} // Blank, ZWJ, ZWNJ etc, with no width fReserved {:1} // General reserved ); TScriptVisAttr_set = set of TScriptVisAttr_enum; PScriptVisAttr = ^TScriptVisAttr; tag_SCRIPT_VISATTR = packed record case Byte of 0: (uJustification: Byte) {:4}; // Justification class 1: (fFlags: TScriptVisAttr_set; fShapeReserved: Byte) {:8}; // Reserved for use by shaping engines end; (* uJustification: Word {:4}; // Justification class fClusterStart: Word {:1}; // First glyph of representation of cluster fDiacritic: Word {:1}; // Diacritic fZeroWidth: Word {:1}; // Blank, ZWJ, ZWNJ etc, with no width fReserved: Word {:1}; // General reserved fShapeReserved: Word {:8}; // Reserved for use by shaping engines end; *) SCRIPT_VISATTR = tag_SCRIPT_VISATTR; {$EXTERNALSYM SCRIPT_VISATTR} TScriptVisAttr = SCRIPT_VISATTR; const MASK_uJustification = $F; // Mask to apply to TScriptVisAttr.uJustification // // //p uJustification: Justification class for this glyph. See SCRIPT_JUSTIFY. // //p fClusterStart: Set for the logically first glyph in every cluster, // even for clusters containing just one glyph. // //p fDiacritic: Set for glyphs that combine with base characters. // //p fZeroWidth: Set by the shaping engine for some, but not all, zero // width characters. ///// ScriptShape // // The ScriptShape function takes a Unicode run and generates glyphs and // visual attributes. // // The number of glyphs generated varies according to the script and the // font. Only for simple scripts and fonts does each Unicode code point // generates a single glyph. // // There is no limit on the number of glyphs generated by a codepoint. // For example, a sophisticated complex script font might choose to // constuct characters from components, and so generate many times as // many glyphs as characters. // // There are also special cases like invalid character representations, // where extra glyphs are added to represent the invalid sequence. // // A reasonable guess might be to provide a glyph buffer 1.5 times the // length of the character buffer, plus a 16 glyph fixed addition for // rare cases like invalid sequenece representation. // // If ScriptShape returns E_OUTOFMEMORY it will be necessary to recall // it, possibly more than once, until a large enough buffer is found. function ScriptShape( hdc: HDC; // In Optional (see under caching) psc: PScriptCache; // InOut Cache handle const pwcChars: PWideChar; // In Logical unicode run cChars: Integer; // In Length of unicode run cMaxGlyphs: Integer; // In Max glyphs to generate psa: PScriptAnalysis; // InOut Result of ScriptItemize (may have fNoGlyphIndex set) pwOutGlyphs: PWord; // Out Output glyph buffer pwLogClust: PWord; // Out Logical clusters psva: PScriptVisAttr; // Out Visual glyph attributes pcGlyphs: PInteger // Out Count of glyphs generated ): HRESULT; stdcall; {$EXTERNALSYM ScriptShape} ///// // // Returns E_OUTOFMEMORY if the output buffer length (cMaxGlyphs) is // insufficient. Note that in this case, as in all error cases, the // content of all output parameters are undefined. // //p psa: Pass the SCRIPT_ANALYSIS field of the SCRIPT_ITEM entry for this // item. (The SCRIPT_ITEM array is returned by ScriptItemize.) // // Clusters are sequenced uniformly within the run, as are glyphs within // the cluster - the fRTL item flag (from ScriptItemize) identifies // whether left to right, or right to left. // //p pwLogClust: has cChars elements - each entry in pwLogClust corresponds // to a character in the input string (pwcChars). The value in each // pwLogCLust entry is the offset of the first glyph in the cluster // that contains this character. // // Example: In the following example, there are four clusters: // 1st cluster: one character represented by one glyph // 2nd cluster: one character represented by 3 glyphs // 3rd cluster: three characters represented by one glyph // 4th cluster: 2 characters represented by three glyphs // // Glyph array: (cg means cluster n glyph m) //c 0 1 2 3 4 5 6 7 //c ------------------------------------------------- //c | c1g1 | c2g1 c2g2 c2g3 | c3g1 | c4g1 c4g2 c4g3 | //c ------------------------------------------------- // // Character array: (cu means cluster n Unicode codepoint m) //c 0 1 2 3 4 5 6 //c -------------------------------------------- //c | c1u1 | c2u1 | c3u1 c3u2 c3u3 | c4u1 c4u2 | //c -------------------------------------------- // // LogClust: (one entry per character gives 1st glyph in cluster //c -------------------------------------------- //c | 0 | 1 | 4 4 4 | 5 5 | //c -------------------------------------------- // // Note that for an RTL run (SCRIPT_ANALYSIS.a.fRTL == TRUE) and when // fLogicalOrder == FALSE (the default), glyphs are generated in visual // order - the reverse of the codepoint order, and the values in the // LogClust array will be descending. // // //p psva: has one visual attribute per glyph and so has maxGlyphs entries. // // // ScriptShape may set the fNoGlyphIndex flag in psa if the font or // OS cannot support glyph indices. // // If fLogicalOrder is requested in psa, glyphs will be always be // generated in the same order as the original Unicode characters. // // If fLogicalOrder is not set, right to left items are generated in // reverse order, so ScriptTextOut does not need to reverse them before // calling ExtTextOut. ///// ScriptPlace // // The ScriptPlace function takes the output of a ScriptShape call and // generates glyph advance width and 2D offset information. // // The composite ABC width for the whole item identifies how much the // glyphs overhang to the left of the start position and to the right of // the length implied by the sum of the advance widths. // // The total advance width of the line is exactly abcA + abcB + abcC. // // abcA and abcC are maintained internally by Uniscribe as proportions // of the cell height represented in 8 bits and are thus roughly +/- 1%. // The total width returned (as the sum of piAdvance, and as the sum of // abcA+abcB+abcC) is accurate to the resolution of the TrueType shaping // engine. // // All glyph related arrays are in visual order unless the fLogicalOrder // flag is set in psa. type PGOffset = ^TGOffset; tagGOFFSET = record du: Longint; dv: Longint; end; GOFFSET = tagGOFFSET; {$EXTERNALSYM GOFFSET} TGOffset = tagGOFFSET; function ScriptPlace( hdc: HDC; // In Optional (see under caching) psc: PScriptCache; // InOut Cache handle const pwGlyphs: PWord; // In Glyph buffer from prior ScriptShape call cGlyphs: Integer; // In Number of glyphs const psva: PScriptVisAttr; // In Visual glyph attributes psa: PScriptAnalysis; // InOut Result of ScriptItemize (may have fNoGlyphIndex set) piAdvance: PInteger; // Out Advance wdiths pGoffset: PGOffset; // Out x,y offset for combining glyph pABC: PABC // Out Composite ABC for the whole run (Optional) ): HRESULT; stdcall; {$EXTERNALSYM ScriptPlace} ///// ScriptTextOut // // The ScriptTextOut function takes the output of both ScriptShape and // ScriptPlace calls and calls the operating system ExtTextOut function // appropriately. If the last parameter is not null, GDI's ExtTextOutW calls // are routed to this function. // // All arrays are in visual order unless the fLogicalOrder flag is set in // psa. function ScriptTextOut( const hdc: HDC; // In OS handle to device context (required) psc: PScriptCache; // InOut Cache handle x: Integer; // In x,y position for first glyph y: Integer; // In fuOptions: LongWord; // In ExtTextOut options const lprc: PRect; // In optional clipping/opaquing rectangle const psa: PScriptAnalysis; // In Result of ScriptItemize const pwcReserved: PWideChar; // In Reserved (requires NULL) iReserved: Integer; // In Reserved (requires 0) const pwGlyphs: PWord; // In Glyph buffer from prior ScriptShape call cGlyphs: Integer; // In Number of glyphs const piAdvance: PInteger; // In Advance widths from ScriptPlace const piJustify: PInteger; // In Justified advance widths (optional) const pGoffset: PGOffset // In x,y offset for combining glyph ): HRESULT; stdcall; ///// // // The caller should normally use SetTextAlign(hdc, TA_RIGHT) before // calling ScriptTextOut with an RTL item inlogical order. // // The piJustify array provides requested cell widths for each glyph. // When the piJustify width of a glyph differs from the unjustified // width (in PiAdvance), space is added to or removed from the glyph // cell at it's trailing edge. The glyph is always aligned with the // leading edge of it's cell. (This rule applies even in visual order.) // // When a glyph cell is extended the extra space is uaually made up by // the addition of white space, however for Arabic scripts, the extra // space is made up by one or more kashida glyphs, unless the extra space // is insufficient for the shortest kashida glyph in the font. (The // width of the shortest kashida is available by calling // ScriptGetFontProperties.) // // piJustify should only be passed if re-justification of the string is // required. Normally pass NULL to this parameter. // // fuOptions may contain ETO_CLIPPED or ETO_OPAQUE (or neither or both). // // Do not use ScriptTextOut to write to a metafile unless you are sure // that the metafile will eventually be played back without any font // substitution. ScriptTextOut record glyph numbers in the metafile. // Since glyph numbers vary considerably from one font to another // such a metafile is unlikely to play back correctly when differant // fonts are substituted. // // For example when a metafile is played back at a different scale // CreateFont requests recorded in the metafile may resolve to bitmap // instead of truetype fonts, or if the metafile is played back on // a different machine requested fonts may not be installed.// // // To write complex scripts in a metafile in a font independant manner, // use ExtTextOut to write the logical characters directly, so that // glyph generation and placement does not occur until the text is // played back. ///// ScriptJustify // // ScriptJustify provides a simple minded implementation of multilingual // justification. // // Sophisticated text formatters may prefer to generate their own delta // dx array by combining their own features with the information returned // by ScriptShape in the SCRIPT_VISATTR array. // // ScriptJustify establishes how much adjustment to make at each glyph // position on the line. It interprets the SCRIPT_VISATTR array generated // by a call to ScriptShape, and gives top priority to kashida, then uses // inter word spacing if there's no kashida points, then uses // intercharacter spacing if there are no inter-word points. // // The justified advance widths generated in ScriptJustify should be // passed to ScriptTextOut in the piJustify paramter. // // ScriptJustify creates a justify array containing updated advance // widths for each glyph. Where a glyphs advance width is increased, it // is expected that the extra width will be rendered to the right of the // glyph, with as white space or, for Arabic text, as kashida. ///// function ScriptJustify( const psva: PScriptVisAttr; // In Collected visual attributes for entire line const piAdvance: PInteger; // In Advance widths from ScriptPlace cGlyphs: Integer; // In Size of all arrays iDx: Integer; // In Desired width change, either increase or descrease iMinKashida: Integer; // In Minimum length of continuous kashida glyph to generate piJustify: PInteger // Out Updated advance widths to pass to ScriptTextOut ): HRESULT; stdcall; type ///// SCRIPT_LOGATTR // // The SCRIPT_LOGATTR structure describes attributes of logical // characters useful when editing and formatting text. // // Note that for wordbreaking and linebreaking, if the first character of // the run passed in is not whitespace, the client needs to check whether // the last character of the previous run is whitespace to determine if // the first character of this run is the start of a word. // // TScriptLogAttr_enum = ( fSoftBreak, // Potential linebreak point fWhiteSpace, // A unicode whitespace character, except NBSP, ZWNBSP fCharStop, // Valid cursor position (for left/right arrow) fWordStop, // Valid cursor position (for ctrl + left/right arrow) fInvalid // Invalid character sequence ); PScriptLogAttr = ^TScriptLogAttr; tag_SCRIPT_LOGATTR = set of TScriptLogAttr_enum; (* fSoftBreak: Byte {:1}; // Potential linebreak point fWhiteSpace: Byte {:1}; // A unicode whitespace character, except NBSP, ZWNBSP fCharStop: Byte {:1}; // Valid cursor position (for left/right arrow) fWordStop: Byte {:1}; // Valid cursor position (for ctrl + left/right arrow) fInvalid: Byte {:1}; // Invalid character sequence fReserved: Byte {:3;} end; *) {$EXTERNALSYM tag_SCRIPT_LOGATTR} SCRIPT_LOGATTR = tag_SCRIPT_LOGATTR; {$EXTERNALSYM SCRIPT_LOGATTR} TScriptLogAttr = SCRIPT_LOGATTR; // // //p fSoftBreak: It would be valid to break the line in front of this // character. This flag is set on the first character of // South-East Asian words. Note that when linebreaking the // client would usually also treat any nonblank following a blank // as a softbreak position, by inspecting the fWhiteSPace flag // below. // //p fWhiteSpace: This character is one of the many Unicode character // that are classified as breakable whitespace. // //p fCharStop: Valid cursor position. Set on most characters, but not // on codepoints inside Indian and South East Asian character // clusters. May be used to implement left and right arrow // operation in editors. // //p fWordStop: Valid position following word advance/retire commonly // implemented at ctrl/left-arrow and ctrl/right-arrow. // May be used to implement ctrl+left and ctrl+right arrow // operation in editors. As with fSoftBreak clients should // normally also inspect the fWhiteSpace flag and treat the // first character after a run of whitespace as the start of a // word. // //p fInvalid: Marks characters which form an invalid or undisplayable // combination. Scripts which can set this flag have the flag // fInvalidLogAttr set in their SCRIPT_PROPERTIES. ///// ScriptBreak // // The ScriptBreak function returns cursor movement and formatting break // positions for an item as an array of SCRIPT_LOGATTRs. To support // mixed formatting within a single word correctly, ScriptBreak should // be passed whole items as returned by ScriptItemize. // // ScriptBreak does not require an hdc and does not execute glyph shaping. // // The fCharStop flag marks cluster boundaries for those scripts where // it is conventional to restrict from moving inside clusters. The same // boundaries could also be inferred by inspecting the pLogCLust array // returned by ScriptShape, however ScriptBreak is considerably faster in // implementation and does not require an hdc to be prepared. // // The fWordStop, fSoftBreak and fWhiteSpace flags are only available // through ScriptBreak. // // Most shaping engines that identify invalid sequences do so by setting // the fInvalid flag in ScriptBreak. The fInvalidLogAttr flag in // ScriptProperties identifies which scripts do this. function ScriptBreak( const pwcChars: PWideChar; // In Logical unicode item cChars: Integer; // In Length of unicode item const psa: PScriptAnalysis; // In Result of earlier ScriptItemize call psla: PScriptLogAttr // Out Logical character attributes ): HRESULT; stdcall; {$EXTERNALSYM ScriptBreak} ///// ScriptCPtoX // // The ScriptCPtoX function returns the x offset from the left end // (!fLogical) or leading edge (fLogical) of a run to either the leading // or the trailing edge of a logical character cluster. // // iCP is the offset of any logical character in the cluster. // // For scripts where the caret may conventionally be placed into the // middle of clusters (e.g. Arabic, Hebrew), the returned X may be // an interpolated position for any codepoint in the line. // // For scripts where the caret is conventionally snapped to the boundaries // of clusters, (e.g. Thai, Indian), the resulting X position will be // snapped to the requested edge of the cluster containing CP. function ScriptCPtoX( iCP: Integer; // In Logical character position in run fTrailing: BOOL; // In Which edge (default - leading) cChars: Integer; // In Count of logical codepoints in run cGlyphs: Integer; // In Count of glyphs in run const pwLogClust: PWord; // In Logical clusters const psva: PScriptVisAttr; // In Visual glyph attributes array const piAdvance: PInteger; // In Advance widths const psa: PScriptAnalysis; // In Script analysis from item attributes piX: PInteger // Out Resulting X position ): HRESULT; stdcall; ///// ScriptXtoCP // // The ScriptXtoCP function converts an x offset from the left end // (!fLogical) or leading edge (fLogical) of a run to a logical // character position and a flag that indicates whether the X position // fell in the leading or the trailing half of the character. // // For scripts where the cursor may conventionally be placed into the // middle of clusters (e.g. Arabic, Hebrew), the returned CP may be // for any codepoint in the line, and fTrailing will be either zero // or one. // // For scripts where the cursor is conventionally snapped to the // boundaries of a cluster, the returned CP is always the position of // the logically first codepoint in a cluster, and fTrailing is either // zero, or the number of codepoints in the cluster. // // Thus the appropriate cursor position for a mouse hit is always the // returned CP plus the value of fTrailing. // // If the X positition passed is not in the item at all, the resulting // position will be the trailing edge of character -1 (for X positions // before the item), or the leading edge of character 'cChars' (for // X positions following the item). function ScriptXtoCP( iX: Integer; // In X offset from left of run cChars: Integer; // In Count of logical codepoints in run cGlyphs: Integer; // In Count of glyphs in run const pwLogClust: PWord; // In Logical clusters const psva: PScriptVisAttr; // In Visual glyph attributes const piAdvance: Integer; // In Advance widths const psa: PScriptAnalysis; // In Script analysis from item attributes piCP: PInteger; // Out Resulting character position piTrailing: PInteger // Out Leading or trailing half flag ): HRESULT; stdcall; ///// Relationship between caret positions, justifications points and clusters // // //t Job | Uniscribe support //t -------------------------------- | -------------------------------------------------------- //t Caret move by character cluster | LogClust or VISATTR.fClusterStart or LOGATTR.fCharStop //t Line breaking between characters | LogClust or VISATTR.fClusterStart or LOGATTR.fCharStop //t Caret move by word | LOGATTR.fWordStop //t Line breaking between words | LOGATTR.fWordStop //t Justification | VISATTR.uJustification // // // ///// Character clusters // // Character clusters are glyph sequences that cannot be split between // lines. // // Some languages (e.g. Thai, Indic) restrict caret placement to points // betwen clusters. This applies both to keyboard initiated caret // movement (e.g. cursor keys) and pointing and clicking with the mouse // (hit testing). // // Uniscribe provides cluster information in both the visual and logical // attributes. If you've called ScriptShape you'll find the cluster // information represented both by sequences of the same value in the // pwLogClust array, and by the fClusterStart flag in the psva // SCRIPT_VISATTR array. // // ScriptBreak also returns the fCharStop flag in the SCRIPT_LOGATTR // array to identify cluster positions. // // // ///// Word break points // // Valid positions for moving the caret when moving in whole words are // marked by the fWordStop flag returned by ScriptBreak. // // Valid positions for breaking lines between words are marked by the // fSoftBreak flag returned by ScriptBreak. // // // ///// Justification // // Justification space or kashida should be inserted where identified by // the uJustificaion field of the SCRIPT_VISATTR. // // When performing inter-character justification, insert extra space // only after glyphs marked with uJustify == SCRIPT_JUSTIFY_CHARACTER. // // // ///// Script specific processing // // Uniscribe provides information about special processing for each // script in the SCRIPT_PROPERTIES array. // // Use the following code during initialisation to get a pointer to // the SCRIPT_PROPERTIES array: // //c const SCRIPT_PROPERTIES **g_ppScriptProperties; // Array of pointers to properties //c int iMaxScript; //c HRESULT hr; // //c hr = ScriptGetProperties(&g_ppScriptProperties, &g_iMaxScript); // // Then inspect the properties of the script of an item 'iItem' as follows: // //c hr = ScriptItemize( ... , pItems, ... ); //c ... //c if (g_ppScriptProperties[pItems[iItem].a.eScript]->fNeedsCaretInfo) { //c // Use ScriptBreak to restrict the caret from entering clusters (for example). //c } // // // SCRIPT_PROPERTIES.fNeedsCaretInfo // // Caret placement should be restricted to cluster // edges for scripts such as Thai and Indian. The fNeedsCaretInfo flag // in SCRIPT_PROPERTIES identifies such languages. // // Note that ScriptXtoCP and ScriptCPtoX automatically apply caret // placement restictions. // // // SCRIPT_PROPERTIES.fNeedsWordBreaking // // For most scripts, word break placement may be // identified by scanning for characters marked as fWhiteSpace in // SCRIPT_LOGATTR, or for glyphs marked as uJustify == // SCRIPT_JUSTIFY_BLANK or SCRIPT_JUSTIFY_ARABIC_BLANK in SCRIPT_VISATTR. // // For languages such as Thai, it is also necessary to call ScriptBreak, // and include character positions marked as fWordStop in SCRIPT_LOGATTR. // Such scripts are marked as fNeedsWordbreaking in SCRIPT_PROPERTIES. // // // SCRIPT_PROPERTIES.fNeedsCharacterJustify // // Languages such as Thai also require inter-character spacing when // justifying (where uJustify == SCRIPT_JUSTIFY_CHARACTER in the // SCRIPT_VISATTR). Such languages are marked as fNeedsCharacterJustify // in SCRIPT_PROPERTIES. // // // SCRIPT_PROPERTIES.fAmbiguousCharSet // // Many Uniscribe scripts do not correspond directly to 8 bit character // sets. For example Unicode characters in the range U+100 through U+024F // represent extended latin shapes used for many languages, including // those supported by EASTEUROPE_CHARSET, TURKISH_CHARSET and // VIETNAMESE_CHARSET. However many of these characters are supported by // more han one of thsese charsets. // fAmbiguousCharset is set for any script token which could contain // characters from a number of these charsets. In these cases the bCharSet // field may contain ANSI_CHARSET or DEFAULT_CHARSET. The Uniscribe client // will generally need to apply futher processing to determine which charset // to use when requesting a font suitable for this run. For example it // determine that the run consists of multiple languages and split it up // to use a different font for each language. ///// Notes on ScriptXtoCP and ScriptCPtoX // // Both functions work only within runs and require the results of a // previous ScriptShape call. // // The client must establish which run a given cursor offset or x // position is within before passing it to ScriptCPtoX or ScriptXtoCP. // // Cluster information in the logical cluster array is used to share // the width of a cluster of glyphs equally among the logical characters // they represent. // // For example, the lam alif glyph is divided into four areas: the // leading half of the lam, the trailing half of the lam, the leading // half of the alif and the trailing half of the alif. // // ScriptXtoCP Understands the caret position conventions of each script. // For Indian and Thai, caret positions are snapped to cluster boundaries, // for Arabic and Hebrew, caret positions are interpolated within clusters. // // ///// Translating mouse hit 'x' offset to caret position // // Conventionally, caret position 'cp' may be selected by clicking either // on the trailing half of character 'cp-1' or on the leading half of // character 'cp'. This may easily be implemented as follows: // //c int iCharPos; //c int iCaretPos //c int fTrailing; // //c ScriptXtoCP(iMouseX, ..., &iCharPos, &fTrailing); //c iCaretPos = iCharPos + fTrailing; // // For scripts that snap the caret to cluster boundaries, ScriptXtoCP // returns ftrailing set to either 0, or the width of the cluster in // codepoints. Thus the above code correctly returns only valid // caret positions. // // ///// Displaying the caret in bidi strings // // In unidirectional text, the leading edge of a character is at the same // place as the trailing edge of the previous character, so there is no // ambiguity in placing the caret between characters. // // In bidirectional text, the caret position between runs of opposing // direction may be ambiguous. // // For example in the left to right paragraph 'helloMAALAS', the last // letter of 'hello' immediately preceeds the first letter of 'salaam'. // The best position to display the caret depends on whether it is // considered to follow the 'o' of 'hello', or to preceed the 's' of // 'salaam'. // ///// Commonly used caret positioning conventions // //t Situation | Visual caret placement //t --------- | ------------------------------------------- //t Typing | Trailing edge of last character typed //t Pasting | Trailing edge of last character pasted //t Caret advancing | Trailing edge of last character passed over //t Caret retiring | Leading edge of last character passed over //t Home | Leading edge of line //t End | Trailing edge of line // // The caret may be positioned as follows: // //c if (advancing) { //c ScriptCPtoX(iCharPos-1, TRUE, ..., &iCaretX); //c } else { //c ScriptCPtoX(iCharPos, FALSE, ..., &iCaretX); //c } // // Or, more simply, given an fAdvancing BOOL restricted to TRUE or FALSE: // //c ScriptCPtoX(iCharPos-fAdvancing, fAdvancing, ..., &iCaretX); // // ScriptCPtoX handles out of range positions logically: it returns the // leading edge of the run for iCharPos <0, and the trailing edge of the // run for iCharPos >=length. ///// ScriptGetLogicalWidths // // Converts visual withs in piAdvance into logical widths, // one per original character, in logical order. // // Ligature glyphs widths are divided evenly amongst the characters // they represent. function ScriptGetLogicalWidths( const psa: PScriptAnalysis; // In Script analysis from item attributes cChars: Integer; // In Count of logical codepoints in run cGlyphs: Integer; // In Count of glyphs in run const piGlyphWidth: PInteger; // In Advance widths const pwLogClust: PWord; // In Logical clusters const psva: PScriptVisAttr; // In Visual glyph attributes piDx: PInteger // Out Logical widths ): HRESULT; stdcall; ///// // ScriptGetLogicalWidths is useful for recording widths in a // font independant manner. By passing the recorded logical widths // to ScriptApplyLogicalWidths, a block of text can be replayed in the // same boundaries with acceptable loss of quality even when the original // font is not available. ///// ScriptApplyLogicalWidth // // Accepts an array of advance widths in logical order, corresponding // one to one with codepoints, and generates an array of glyph widths // suitable for passing to the piJustify parameter of ScriptTextOut. // // ScriptApplyLogicalWidth may be used to reapply logical widths // obtained with ScriptGetLogicalWidths. It may be useful in situations // such as metafiling, where it is necessary to record and reapply // advance width information in a font independant manner. function ScriptApplyLogicalWidth( const piDx: PInteger; // In Logical dx array to apply cChars: Integer; // In Count of logical codepoints in run cGlyphs: Integer; // In Glyph count const pwLogClust: PWORD; // In Logical clusters const psva: PScriptVisAttr; // In Visual attributes from ScriptShape/Place const piAdvance: PInteger; // In Glyph advance widths from ScriptPlace const psa: PScriptAnalysis; // In Script analysis from item attributes pABC: PABC; // InOut Updated item ABC width (optional) piJustify: PInteger // Out Resulting glyph advance widths for ScriptTextOut ): HRESULT; stdcall; ///// //p piDx: Pointer to an array of dx widths in logical order, one per codepoint. // //p cChars: Count of the logical codepoints in the run. // //p cGlyphs: Glyph count. // //p pwLogClust: Pointer to an array of logical clusters from ScriptShape // //p psva: Pointer to an array of visual attributes from ScriptShape and // updated by ScriptPlace. // //p piAdvance: Pointer to an array of glyph advance widths from ScriptPlace. // //p psa: Pointer to a SCRIPT_ANALYSIS structure from ScriptItemize and // updated by ScriptShape and SriptPlace.. // //p pABC: Pointer to the run overall ABC width (optional). If present, // when the function is called, it should contain the run ABC width // returned by ScriptPlace; when the function returns, the ABC width // has been updated to match the new widths. // //p piJustify:Pointer to an array of the resulting glyph advance widths. // This is suitable for passing to the piJustify parameter of ScriptTextOut. ///// ScriptGetCMap // // ScriptGetCMap may be used to determine which characters in a run // are supported by the selected font. // // It returns glyph indices of Unicode characters according to Truetype // Cmap table, or standard Cmap implemented for old style fonts. The // glyph indices are returned in the same order as the input string. // // The caller may scan the returned glyph buffer looking for the default // glyph to determine which characters are not available. (The default // glyph index for the selected font should be determined by calling // ScriptGetFontProperties). // // The return value indicates the presence of any missing glyphs. const SGCM_RTL = $00000001; // Return mirrored glyph for mirrorable Unicode codepoints function ScriptGetCMap( hdc: HDC; // In Optional (see notes on caching) psc: PScriptCache; // InOut Address of Cache handle const pwcInChars: PWideChar; // In Unicode codepoint(s) to look up cChars: Integer; // In Number of characters dwFlags: DWORD; // In Flags such as SGCM_RTL pwOutGlyphs: PWord // Out Array of glyphs, one per input character ): HRESULT; stdcall; ///// // returns S_OK - All unicode codepoints were present in the font // S_FALSE - Some of the Unicode codepoints were mapped to the default glyph // E_HANDLE - font or system does not support glyph indices ///// ScriptGetGlyphABCWidth // // Returns ABC width of a given glyph. // May be useful for drawing glyph charts. Should not be used for // run of the mill complex script text formatting. function ScriptGetGlyphABCWidth( hdc: HDC; // In Optional (see notes on caching) psc: PScriptCache; // InOut Address of Cache handle wGlyph: Word; // In Glyph pABC: PABC // Out ABC width ): HRESULT; stdcall; type ///// // returns S_OK - Glyph width returned // E_HANDLE - font or system does not support glyph indices ///// SCRIPT_PROPERTIES // TScriptProperties_enum = ( fNumeric, {:1} fComplex, {:1} // Script requires special shaping or layout fNeedsWordBreaking, {:1} // Requires ScriptBreak for word breaking information fNeedsCaretInfo, {:1} // Requires caret restriction to cluster boundaries bCharSet, {:8} // Charset to use when creating font fControl, {:1} // Contains only control characters fPrivateUseArea, {:1} // This item is from the Unicode range U+E000 through U+F8FF fNeedsCharacterJustify,{:1} // Requires inter-character justification fInvalidGlyph, {:1} // Invalid combinations generate glyph wgInvalid in the glyph buffer fInvalidLogAttr, {:1} // Invalid combinations are marked by fInvalid in the logical attributes fCDM, {:1} // Contains Combining Diacritical Marks fAmbiguousCharSet, {:1} // Script does not correspond 1//:1 with a charset fClusterSizeVaries, {:1} // Measured cluster width depends on adjacent clusters fRejectInvalid {:1} // Invalid combinations should be rejected ); TScriptProperties_set = set of TScriptProperties_enum; PScriptProperties = ^TScriptProperties; SCRIPT_PROPERTIES = packed record langid: Word {:16}; // Primary and sublanguage associated with script fFlags: TScriptProperties_set; end; (* langid: DWORD {:16}; // Primary and sublanguage associated with script fNumeric: DWORD {:1}; fComplex: DWORD {:1}; // Script requires special shaping or layout fNeedsWordBreaking: DWORD {:1}; // Requires ScriptBreak for word breaking information fNeedsCaretInfo: DWORD {:1}; // Requires caret restriction to cluster boundaries bCharSet: DWORD {:8}; // Charset to use when creating font fControl: DWORD {:1}; // Contains only control characters fPrivateUseArea: DWORD {:1}; // This item is from the Unicode range U+E000 through U+F8FF fNeedsCharacterJustify: DWORD {:1}; // Requires inter-character justification fInvalidGlyph: DWORD {:1}; // Invalid combinations generate glyph wgInvalid in the glyph buffer fInvalidLogAttr: DWORD {:1}; // Invalid combinations are marked by fInvalid in the logical attributes fCDM: DWORD {:1}; // Contains Combining Diacritical Marks fAmbiguousCharSet: DWORD {:1}; // Script does not correspond 1//:1 with a charset fClusterSizeVaries: DWORD {:1}; // Measured cluster width depends on adjacent clusters fRejectInvalid: DWORD {:1}; // Invalid combinations should be rejected end; *) {$EXTERNALSYM SCRIPT_PROPERTIES} TScriptProperties = SCRIPT_PROPERTIES; // //p langid: Language associated with this script. When a script is used for many languages, // langid id represents a default language. For example, Western script is represented // by LANG_ENGLISH although it is also used for French, German, Spanish etc. // //p fNumeric: Script contains numerics and characters used in conjunction with numerics // by the rules of the Unicode bidirectional algorithm. For example // dollar sign and period are classified as numeric when adjacent to or in between // digits. // //p fComplex: Indicates a script that requires complex script handling. If fComplex is false // the script contains no combining characters and requires no contextual shaping or reordering. // //p fNeedsWordBreaking: A script, such as Thai, which requires algorithmic wordbreaking. // Use ScriptBreak to obtain a wordbreak points using the standard system wordbreaker. // //p fNeedsCaretInfo: A script, such as Thai and Indian, where the caret may not be placed // inside a cluster. To determine valid caret positions inspect the fCharStop flag in the // logical attributes returned by ScriptBreak, or compare adjacent values in the pwLogClust // array returned by ScriptShape. // //p bCharSet: Nominal charset associated with script. May be used in a logfont when creating // a font suitable for displaying this script. Note that for new scripts where there // is no charset defined, bCharSet may be innapropriate and DEFAULT_CHARSET should // be used instead - see the description of fAmbiguousCharSet below. // //p fControl: contains control characters. // //p fPrivateUseArea: The Unicode range U+E000 through U+F8FF. // //p fNeedsCharacterJustify: A script, such as Thai, where justification is conventionally // achieved by increasing the space between all letters, not just between words. // //p fInvalidGlyph: A script for which ScriptShape generates an invalid glyph // to represent invalid sequences. The glyph index of the invalid glyph for // a particular font may be obtained by calling ScriptGetFontProperties. // //p fInvalidLogAttr: A script for which ScriptBreak sets the fInvalid flag // in the logical attributes to mark invalid sequences. // //p fCDM: Implies that an item analysed by ScriptItemize included combining // diacritical marks (U+0300 through U+36F). // //p fAmbiguousCharSet: No single legacy charset supports this script. // For example the extended Latin Extended-A Unicode range includes // characters from the EASTUROPE_CHARSET, the TURKISH_CHARSET and the // BALTIC_CHARSET. It also contains characters that are not available // in any legacy charset. Use DEFAULT_CHARSET when creating fonts to // display parts of this run. // //p fClusterSizeVaries: A script, such as Arabic, where contextual shaping // may cause a string to increase in size when removing characters. // //p fRejectInvalid: A script, such as Thai, where invalid sequences conventionally // cause an editor such as notepad to beep, and ignore keypresses. ///// ScriptGetProperties // // ScriptGetProperties returns the address of a table that maps a // script in a SCRIPT_ANALYSIS uScript field to properties including // the primary language associated with that script, whether it's // numeric and whether it's complex. function ScriptGetProperties( out ppSp: PScriptProperties; // Out Receives pointer to table of pointers to properties indexed by script out piNumScripts: Integer // Out Receives number of scripts (valid values are 0 through NumScripts-1) ): HRESULT; stdcall; type ///// SCRIPT_FONTPROPERTIES // PScriptFontProperties = ^TScriptFontProperties; SCRIPT_FONTPROPERTIES = record cBytes: Integer; // Structure length wgBlank: Word; // Blank glyph wgDefault: Word; // Glyph used for Unicode values not present in the font wgInvalid: Word; // Glyph used for invalid character combinations (especially in Thai) wgKashida: Word; // Shortest continuous kashida glyph in the font, -1 if doesn't exist iKashidaWidth: Integer;// Widths of shortest continuous kashida glyph in the font end; {$EXTERNALSYM SCRIPT_FONTPROPERTIES} TScriptFontProperties = SCRIPT_FONTPROPERTIES; ///// ScriptGetFontProperties // // Returns information from the font cache function ScriptGetFontProperties( hdc: HDC; // In Optional (see notes on caching) psc: PScriptCache; // InOut Address of Cache handle sfp: PScriptFontProperties // Out Receives properties for this font ): HRESULT; stdcall; ///// ScriptCacheGetHeight // // function ScriptCacheGetHeight( hdc: HDC; // In Optional (see notes on caching) psc: PScriptCache; // InOut Address of Cache handle tmHeight: PLongint // Out Receives font height in pixels ): HRESULT; stdcall; const ///// ScriptStringAnalyse // // SSA_PASSWORD = $00000001; // Input string contains a single character to be duplicated iLength times SSA_TAB = $00000002; // Expand tabs SSA_CLIP = $00000004; // Clip string at iReqWidth SSA_FIT = $00000008; // Justify string to iReqWidth SSA_DZWG = $00000010; // Provide representation glyphs for control characters SSA_FALLBACK = $00000020; // Use fallback fonts SSA_BREAK = $00000040; // Return break flags (character and word stops) SSA_GLYPHS = $00000080; // Generate glyphs, positions and attributes SSA_RTL = $00000100; // Base embedding level 1 SSA_GCP = $00000200; // Return missing glyphs and LogCLust with GetCharacterPlacement conventions SSA_HOTKEY = $00000400; // Replace '&' with underline on subsequent codepoint SSA_METAFILE = $00000800; // Write items with ExtTextOutW Unicode calls, not glyphs SSA_LINK = $00001000; // Apply FE font linking/association to non-complex text SSA_HIDEHOTKEY = $00002000; // Remove first '&' from displayed string SSA_HOTKEYONLY = $00002400; // Display underline only. SSA_FULLMEASURE = $04000000; // Internal - calculate full width and out the number of chars can fit in iReqWidth. SSA_LPKANSIFALLBACK = $08000000; // Internal - enable FallBack for all LPK Ansi calls Except BiDi hDC calls SSA_PIDX = $10000000; // Internal SSA_LAYOUTRTL = $20000000; // Internal - Used when DC is mirrored SSA_DONTGLYPH = $40000000; // Internal - Used only by GDI during metafiling - Use ExtTextOutA for positioning SSA_NOKASHIDA = $80000000; // Internal - Used by GCP to justify the non Arabic glyphs only. // // //p SSA_HOTKEY: Note that SSA_HOTKEY and SSA_HIDEHOTKEY remove the // hotkey '&' character from further processing, so functions // such as ScriptString_pLogAttr return arrays based on a string // which excludes the '&'. type ///// SCRIPT_TABDEF // // Defines tabstop positions for ScriptStringAnalyse (ignored unless SSA_TAB passed) // PScriptTabDef = ^TScriptTabDef; tag_SCRIPT_TABDEF = record cTabStops: Integer; // Number of entries in pTabStops array iScale: Integer; // Scale factor for pTabStops (see below) pTabStops: PInteger; // Pointer to array of one or more tab stops iTabOrigin: Integer; // Initial offset for tab stops (logical units) end; {$EXTERNALSYM tag_SCRIPT_TABDEF} SCRIPT_TABDEF = tag_SCRIPT_TABDEF; {$EXTERNALSYM SCRIPT_TABDEF} TScriptTabDef = tag_SCRIPT_TABDEF; // // //p cTabStops: Number of entries in the pTabStops array. If zero, tabstops // are every 8 average character widths. If one, all tabstops are // the length of the first entry in pTabStops. If more than one, // the first cTabStops are as specified in the pTabStops array, // subsequent tabstops are every 8 average characters from the last // tabstop in the array. // //p iScale: Scale factor for iTabOrigin and pTabStops entries. Values are // converted to device coordinates by multiplying by iScale then // dividing by 4. If values are already in device units, set iScale to // 4. If values are in dialog units, set iScale to the average char // width of the dialog font. If values are multiples of the average // character width for the selected font, set iScale to 0. // //p pTabStops: Array of cTabStops entries. Each entry specifies a // tabstop position. Positive values give nearedge alignment, // negative values give faredge alignment. // //p iTabOrigin: Tabs are considered to start iTabOrigin before the // beginning of the string. Helps with multiple tabbed // outputs on the same line. ///// ScriptStringAnalyse // // cString - Input string must contain at least one character // // hdc - required if SSA_GLYPH requested. Optional for SSA_BREAK. // If present the current font in the hdc is inspected and if a symbolic // font the character string is treated as a single neutral SCRIPT_UNDEFINED item. // // Note that the uBidiLevel field in the initial SCRIPT_STATE value // is ignored - the uBidiLevel used is derived from the SSA_RTL // flag in combination with the layout of the hdc. SCRIPT_STRING_ANALYSIS = Pointer; {$EXTERNALSYM SCRIPT_STRING_ANALYSIS} TScriptStringAnalysis = SCRIPT_STRING_ANALYSIS; PScriptStringAnalysis = ^TScriptStringAnalysis; function ScriptStringAnalyse( hdc: HDC; //In Device context (required) const pString: Pointer; //In String in 8 or 16 bit characters cString: Integer; //In Length in characters (Must be at least 1) cGlyphs: Integer; //In Required glyph buffer size (default cString*1.5 + 16) iCharset: Integer; //In Charset if an ANSI string, -1 for a Unicode string dwFlags: DWORD; //In Analysis required iReqWidth: Integer; //In Required width for fit and/or clip psControl: PScriptControl; //In Analysis control (optional) psState: PScriptState; //In Analysis initial state (optional) const piDx: PInteger; //In Requested logical dx array pTabdef: PScriptTabDef; //In Tab positions (optional) const pbInClass: PByte; //In Legacy GetCharacterPlacement character classifications (deprecated) pssa: PScriptStringAnalysis //Out Analysis of string ): HRESULT; stdcall; ///// ScriptStringFree - free a string analysis // // function ScriptStringFree( pssa: PScriptStringAnalysis //InOut Address of pointer to analysis ): HRESULT; stdcall; ///// ScriptStringSize // // returns a pointer to the size (width and height) of an analysed string // // Note that the SIZE pointer remains valid only until the // SCRIPT_STRING_ANALYSIS is passed to ScriptStringFree. function ScriptString_pSize( ssa: TScriptStringAnalysis ): {const} PSize; stdcall; ///// ScriptString_pcOutChars // // returns pointer to length of string after clipping (requires SSA_CLIP set) // // Note that the int pointer remains valid only until the // SCRIPT_STRING_ANALYSIS is passed to ScriptStringFree. function ScriptString_pcOutChars( ssa: TScriptStringAnalysis ): {const} PInteger; stdcall; ///// ScriptString_pLogAttr // // returns pointer to logical attributes buffer in a SCRIPT_STRING_ANALYSIS // // Note that the buffer pointer remains valid only until the // SCRIPT_STRING_ANALYSIS is passed to ScriptStringFree. // // The logical attribute array contains *ScriptString_pcOutChars(ssa) // entries. function ScriptString_pLogAttr( ssa: TScriptStringAnalysis ): {const} PScriptLogAttr; stdcall; ///// ScriptStringGetOrder // // Creates an array mapping original character position to glyph position. // // Treats clusters as they were in legacy systems - Unless a cluster // contains more glyphs than codepoints, each glyph is referenced at // least once from the puOrder array. // // Requires SSA_GLYPHS requested in original ScriptStringAnalyse call. // // The puOrder parameter should address a buffer containing room for // at least *ScriptString_pcOutChars(ssa) ints. function ScriptStringGetOrder( ssa: TScriptStringAnalysis; puOrder: PLongWord ): HRESULT; stdcall; ///// ScriptStringCPtoX // // Return x coordinate for leading or trailing edge of character icp. function ScriptStringCPtoX( ssa: TScriptStringAnalysis; //In String analysis icp: Integer; //In Caret character position fTrailing: BOOL; //In Which edge of icp out pX: Integer //Out Corresponding x offset ): HRESULT; stdcall; ///// ScriptStringXtoCP // // function ScriptStringXtoCP( ssa: TScriptStringAnalysis; // In iX: Integer; // In piCh: PInteger; // Out piTrailing: PInteger // Out ): HRESULT; stdcall; ///// ScriptStringGetLogicalWidths // // Converts visual withs in psa->piAdvance into logical widths, // one per original character, in logical order. // // Requires SSA_GLYPHS requested in original ScriptStringAnalyse call. // // The piDx parameter should address a buffer containing room for // at least *ScriptString_pcOutChars(ssa) ints. function ScriptStringGetLogicalWidths( ssa: TScriptStringAnalysis; out piDx: Integer): HRESULT; stdcall; ///// ScriptStringValidate // // Scans the string analysis for invalid glyphs. // // Only glyphs generated by scripts that can generate invalid glyphs // are scanned. // // returns S_OK - no invalid glyphs are present // S_FALSE - one or more invalid glyphs are present function ScriptStringValidate( ssa: TScriptStringAnalysis): HRESULT; stdcall; ///// ScriptStringOut // // Displays the string generated by a prior ScriptStringAnalyze call, // then optionally adds highlighting corresponding to a logical selection. // // Requires SSA_GLYPHS requested in original ScriptStringAnalyse call. function ScriptStringOut( ssa: TScriptStringAnalysis; //In Analysis with glyphs iX: Integer; //In iY: Integer; //In uOptions: LongWord; //In ExtTextOut options const prc: PRect; //In Clipping rectangle (iff ETO_CLIPPED) iMinSel: Integer; //In Logical selection. Set iMinSel>=iMaxSel for no selection iMaxSel: Integer; //In fDisabled: BOOL //In If disabled, only the background is highlighted. ): HRESULT; stdcall; const ///// // uOptions may nclude only ETO_CLIPPED or ETO_OPAQUE. ///// ScriptIsComplex // // Determines whether a Unicode string requires complex script processing // // The dwFlags parameter may include the following requests // SIC_COMPLEX = 1; // Treat complex script letters as complex SIC_ASCIIDIGIT = 2; // Treat digits U+0030 through U+0039 as complex SIC_NEUTRAL = 4; // Treat neutrals as complex // // SIC_COMPLEX: Should normally set. Causes complex script letters to // be treated as complex. // // SIC_ASCIIDIGIT: Set this flag if the string would be displayed with // digit substitution enabled. If you are following the users NLS // settings using the ScriptRecordDigitSubstitution API, you can pass // scriptDigitSubstitute.DigitSubstitute != SCRIPT_DIGITSUBSTITUTE_NONE. // // SIC_NEUTRAL: Set this flag if you may be displaying the string with // right-to-left reading order. When this flag is set, neutral characters // are considered as complex. // // // Returns S_OK if string requires complex script processing, // S_FALSE if string contains only characters laid out side by // side from left to right. function ScriptIsComplex( const pwcInChars: PWideChar; //In String to be tested cInChars: Integer; //In Length in characters dwFlags: DWORD //In Flags (see above) ): HRESULT; stdcall; type ///// ScriptRecordDigitSubstitution // // Reads NLS native digit and digit substitution settings and records // them in the SCRIPT_DIGITSUBSTITUTE structure. // // PScriptDigitSubstitute = ^TScriptDigitSubstitute; tag_SCRIPT_DIGITSUBSTITUTE = packed record NationalDigitLanguage: Word {:16}; // Language for native substitution TraditionalDigitLanguage: Word {:16}; // Language for traditional substitution DigitSubstitute: Byte {:8}; // Substitution type bReserved: Byte; wReserved: Word; dwReserved: DWORD; // Reserved end; (* NationalDigitLanguage: DWORD {:16}; // Language for native substitution TraditionalDigitLanguage: DWORD {:16}; // Language for traditional substitution DigitSubstitute: DWORD {:8}; // Substitution type dwReserved: DWORD; // Reserved end; *) {$EXTERNALSYM tag_SCRIPT_DIGITSUBSTITUTE} SCRIPT_DIGITSUBSTITUTE = tag_SCRIPT_DIGITSUBSTITUTE; {$EXTERNALSYM SCRIPT_DIGITSUBSTITUTE} TScriptDigitSubstitute = tag_SCRIPT_DIGITSUBSTITUTE; // // //p NationalDigitLanguage: Standard digits for the selected locale as // defined by the countries standard setting authority. // //p TraditionalDigitLangauge: Digits originally used with the locales // script. // //p DigitSubstitute: Selects between None, Context, National and // Traditional. See ScriptApplyDigitSubstitution below for // constant definitions. // // Although most complex scripts have their own associated digits, many // countries using those scripts use western (so called // 'Arabic') digits as their standard. NationalDigitLanguage reflects the // digits used as standard, and is set from // the NLS data for the locale. // On Windows 2000 the national digit langauge can be // adjusted to any digit script with the control panel/regional // options/numbers/Standard digits listbox. // // The TraditionalDigitLanguage for a locale is derived directly from the // script used by that locale. function ScriptRecordDigitSubstitution( Locale: LCID; // In LOCALE_USER_DEFAULT or desired locale out psds: TScriptDigitSubstitute // Out Digit substitution settings ): HRESULT; stdcall; ///// //p Locale: NLS locale to be queried. Should usually be set to // LOCALE_USER_DEFAULT. Alternatively may be passed as a locale // combined with LOCALE_NOUSEROVERRIDE to obtain default settings // for a given locale. Note that context digit substitution is // supported only in ARABIC and FARSI locales. In other locales, // context digit is mapped to no substitution. // //p psds: Pointer to SCRIPT_DIGITSUBSTITUTE. This structure may be passed // later to ScriptApplyDigitSubstitution. // //p returns: E_INVALIDARG if Locale is invalid or not installed. E_POINTER // if psds is NULL. Otherwise S_OK. // // For performance reasons, you should not call // ScriptRecordDigitSubstitution frequently. In particular it would be a // considerable overhead to call it every time you call ScriptItemize // or ScriptStringAnalyse. // // Instead, you may choose to save the SCRIPT_DIGITSUBSTITUTE // structure, and update it only when you receive a // WM_SETTINGCHANGE message or when a RegNotifyChangeKeyValue // call in a dedicated thread indicates a change in the registry // under HKCU\Control Panel\\International. // // The normal way to call this function is simply // //c SCRIPT_DIGITSUBSTITUTE sds; //c ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &sds); // // Then every time you itemize, you'd use the results like this: // //c SCRIPT_CONTROL sc = {0}; //c SCRIPT_STATE ss = {0}; // //c ScriptApplyDigitSubstitution(&sds, &sc, &ss); // // ///// ScriptApplyDigitSubstitution // // Aplies the digit substitution settings recorded in a // SCRIPT_DIGIT_SUBSTITUTE structure to the SCRIPT_CONTROL and // SCRIPT_STATE structures. // // The DigitSubstitute field of the SCRIPT_DIGITSUBSTITUTE structure // is normally set by ScriptRecordDigitSubstitution, however it may // be replaced by any one of the following values: // // const SCRIPT_DIGITSUBSTITUTE_CONTEXT = 0; // Substitute to match preceeding letters SCRIPT_DIGITSUBSTITUTE_NONE = 1; // No substitution SCRIPT_DIGITSUBSTITUTE_NATIONAL = 2; // Substitute with official national digits SCRIPT_DIGITSUBSTITUTE_TRADITIONAL = 3; // Substitute with traditional digits of the locale // // //p SCRIPT_DIGITSUBSTITUTE_CONTEXT: Digits U+0030 - U+0039 will be // substituted according to the language of prior letters. Before // any letters, digits will be substituted according to the // TraditionalDigitLangauge field of the SCRIPT_DIGIT_SUBSTITUTE // structure. This field is normally set to the primary language of // the Locale passed to ScriptRecordDigitSubstitution. // //p SCRIPT_DIGITSUBSTITUTE_NONE: Digits will not be substituted. Unicode // values U+0030 to U+0039 will be displayed with Arabic (i.e. // Western) numerals. // //p SCRIPT_DIGITSUBSTITUTE_NATIONAL: Digits U+0030 - U+0039 will be // substituted according to the NationalDigitLangauge field of // the SCRIPT_DIGIT_SUBSTITUTE structure. This field is normally // set to the national digits returned for the NLS LCTYPE // LOCALE_SNATIVEDIGITS by ScriptRecordDigitSubstitution. // //p SCRIPT_DIGITSUBSTITUTE_TRADITIONAL: Digits U+0030 - U+0039 will be // substituted according to the TraditionalDigitLangauge field of // the SCRIPT_DIGIT_SUBSTITUTE structure. This field is normally // set to the primary language of the Locale passed to // ScriptRecordDigitSubstitution. function ScriptApplyDigitSubstitution( const psds: PScriptDigitSubstitute; // In Digit substitution settings psc: PScriptControl; // Out Script control structure pss: PScriptState // Out Script state structure ): HRESULT; stdcall; ///// //p psds: Pointer to SCRIPT_DIGITSUBSTITUTE structure recorded earlier. // If NULL, ScriptApplyDigitSubstitution calls // ScriptRecordDigitSubstitution with LOCALE_USER_DEFAULT. // //p psc: SCRIPT_CONTROL structure. The scContextDigits and uDefaultLanguage // fields will be updated. // //p pss: SCRIPT_CONTROL structure. The ssDigitSubstitute field will be // updated. // //p returns: E_INVALIDARG if the DigitSubstitute field of the // SCRIPT_DIGITSUBSTITUTE structure is unrecognised, else S_OK; var Usp10IsInstalled: Boolean; implementation uses SysUtils; const Usp10DLL = 'usp10.dll'; var Usp10DllModule: HMODULE = 0; function GetUsp10DllModule: HMODULE; begin if Usp10DllModule = 0 then begin Usp10DllModule := SafeLoadLibrary(Usp10DLL); if Usp10DllModule <= HINSTANCE_ERROR then Usp10DllModule := 0; end; Result := Usp10DllModule; end; procedure GetProcedureAddress(var P: Pointer; const ModuleName, ProcName: string); begin if not Assigned(P) then begin P := Pointer(GetProcAddress(Usp10DllModule, PAnsiChar(AnsiString(ProcName)))); if not Assigned(P) or (Usp10DllModule = 0) then RaiseLastOSError; end; end; var _ScriptFreeCache: Pointer = nil; function ScriptFreeCache; begin if _ScriptFreeCache = nil then GetProcedureAddress(_ScriptFreeCache, Usp10DLL, 'ScriptFreeCache'); asm MOV ESP, EBP POP EBP JMP [_ScriptFreeCache] end; end; var _ScriptItemize: Pointer = nil; function ScriptItemize; begin if _ScriptItemize = nil then GetProcedureAddress(_ScriptItemize, Usp10DLL, 'ScriptItemize'); asm MOV ESP, EBP POP EBP JMP [_ScriptItemize] end; end; var _ScriptLayout: Pointer = nil; function ScriptLayout; begin if _ScriptLayout = nil then GetProcedureAddress(_ScriptLayout, Usp10DLL, 'ScriptLayout'); asm MOV ESP, EBP POP EBP JMP [_ScriptLayout] end; end; var _ScriptShape: Pointer = nil; function ScriptShape; begin if _ScriptShape = nil then GetProcedureAddress(_ScriptShape, Usp10DLL, 'ScriptShape'); asm MOV ESP, EBP POP EBP JMP [_ScriptShape] end; end; var _ScriptPlace: Pointer = nil; function ScriptPlace; begin if _ScriptPlace = nil then GetProcedureAddress(_ScriptPlace, Usp10DLL, 'ScriptPlace'); asm MOV ESP, EBP POP EBP JMP [_ScriptPlace] end; end; var _ScriptTextOut: Pointer = nil; function ScriptTextOut; begin if _ScriptTextOut = nil then GetProcedureAddress(_ScriptTextOut, Usp10DLL, 'ScriptTextOut'); asm MOV ESP, EBP POP EBP JMP [_ScriptTextOut] end; end; var _ScriptJustify: Pointer = nil; function ScriptJustify; begin if _ScriptJustify = nil then GetProcedureAddress(_ScriptJustify, Usp10DLL, 'ScriptJustify'); asm MOV ESP, EBP POP EBP JMP [_ScriptJustify] end; end; var _ScriptBreak: Pointer = nil; function ScriptBreak; begin if _ScriptBreak = nil then GetProcedureAddress(_ScriptBreak, Usp10DLL, 'ScriptBreak'); asm MOV ESP, EBP POP EBP JMP [_ScriptBreak] end; end; var _ScriptCPtoX: Pointer = nil; function ScriptCPtoX; begin if _ScriptCPtoX = nil then GetProcedureAddress(_ScriptCPtoX, Usp10DLL, 'ScriptCPtoX'); asm MOV ESP, EBP POP EBP JMP [_ScriptCPtoX] end; end; var _ScriptXtoCP: Pointer = nil; function ScriptXtoCP; begin if _ScriptXtoCP = nil then GetProcedureAddress(_ScriptXtoCP, Usp10DLL, 'ScriptXtoCP'); asm MOV ESP, EBP POP EBP JMP [_ScriptXtoCP] end; end; var _ScriptGetLogicalWidths: Pointer = nil; function ScriptGetLogicalWidths; begin if _ScriptGetLogicalWidths = nil then GetProcedureAddress(_ScriptGetLogicalWidths, Usp10DLL, 'ScriptGetLogicalWidths'); asm MOV ESP, EBP POP EBP JMP [_ScriptGetLogicalWidths] end; end; var _ScriptApplyLogicalWidth: Pointer = nil; function ScriptApplyLogicalWidth; begin if _ScriptApplyLogicalWidth = nil then GetProcedureAddress(_ScriptApplyLogicalWidth, Usp10DLL, 'ScriptApplyLogicalWidth'); asm MOV ESP, EBP POP EBP JMP [_ScriptApplyLogicalWidth] end; end; var _ScriptGetCMap: Pointer = nil; function ScriptGetCMap; begin if _ScriptGetCMap = nil then GetProcedureAddress(_ScriptGetCMap, Usp10DLL, 'ScriptGetCMap'); asm MOV ESP, EBP POP EBP JMP [_ScriptGetCMap] end; end; var _ScriptGetGlyphABCWidth: Pointer = nil; function ScriptGetGlyphABCWidth; begin if _ScriptGetGlyphABCWidth = nil then GetProcedureAddress(_ScriptGetGlyphABCWidth, Usp10DLL, 'ScriptGetGlyphABCWidth'); asm MOV ESP, EBP POP EBP JMP [_ScriptGetGlyphABCWidth] end; end; var _ScriptGetProperties: Pointer = nil; function ScriptGetProperties; begin if _ScriptGetProperties = nil then GetProcedureAddress(_ScriptGetProperties, Usp10DLL, 'ScriptGetProperties'); asm MOV ESP, EBP POP EBP JMP [_ScriptGetProperties] end; end; var _ScriptGetFontProperties: Pointer = nil; function ScriptGetFontProperties; begin if _ScriptGetFontProperties = nil then GetProcedureAddress(_ScriptGetFontProperties, Usp10DLL, 'ScriptGetFontProperties'); asm MOV ESP, EBP POP EBP JMP [_ScriptGetFontProperties] end; end; var _ScriptCacheGetHeight: Pointer = nil; function ScriptCacheGetHeight; begin if _ScriptCacheGetHeight = nil then GetProcedureAddress(_ScriptCacheGetHeight, Usp10DLL, 'ScriptCacheGetHeight'); asm MOV ESP, EBP POP EBP JMP [_ScriptCacheGetHeight] end; end; var _ScriptStringAnalyse: Pointer = nil; function ScriptStringAnalyse; begin if _ScriptStringAnalyse = nil then GetProcedureAddress(_ScriptStringAnalyse, Usp10DLL, 'ScriptStringAnalyse'); asm MOV ESP, EBP POP EBP JMP [_ScriptStringAnalyse] end; end; var _ScriptStringFree: Pointer = nil; function ScriptStringFree; begin if _ScriptStringFree = nil then GetProcedureAddress(_ScriptStringFree, Usp10DLL, 'ScriptStringFree'); asm MOV ESP, EBP POP EBP JMP [_ScriptStringFree] end; end; var _ScriptString_pSize: Pointer = nil; function ScriptString_pSize; begin if _ScriptString_pSize = nil then GetProcedureAddress(_ScriptString_pSize, Usp10DLL, 'ScriptString_pSize'); asm MOV ESP, EBP POP EBP JMP [_ScriptString_pSize] end; end; var _ScriptString_pcOutChars: Pointer = nil; function ScriptString_pcOutChars; begin if _ScriptString_pcOutChars = nil then GetProcedureAddress(_ScriptString_pcOutChars, Usp10DLL, 'ScriptString_pcOutChars'); asm MOV ESP, EBP POP EBP JMP [_ScriptString_pcOutChars] end; end; var _ScriptString_pLogAttr: Pointer = nil; function ScriptString_pLogAttr; begin if _ScriptString_pLogAttr = nil then GetProcedureAddress(_ScriptString_pLogAttr, Usp10DLL, 'ScriptString_pLogAttr'); asm MOV ESP, EBP POP EBP JMP [_ScriptString_pLogAttr] end; end; var _ScriptStringGetOrder: Pointer = nil; function ScriptStringGetOrder; begin if _ScriptStringGetOrder = nil then GetProcedureAddress(_ScriptStringGetOrder, Usp10DLL, 'ScriptStringGetOrder'); asm MOV ESP, EBP POP EBP JMP [_ScriptStringGetOrder] end; end; var _ScriptStringCPtoX: Pointer = nil; function ScriptStringCPtoX; begin if _ScriptStringCPtoX = nil then GetProcedureAddress(_ScriptStringCPtoX, Usp10DLL, 'ScriptStringCPtoX'); asm MOV ESP, EBP POP EBP JMP [_ScriptStringCPtoX] end; end; var _ScriptStringXtoCP: Pointer = nil; function ScriptStringXtoCP; begin if _ScriptStringXtoCP = nil then GetProcedureAddress(_ScriptStringXtoCP, Usp10DLL, 'ScriptStringXtoCP'); asm MOV ESP, EBP POP EBP JMP [_ScriptStringXtoCP] end; end; var _ScriptStringGetLogicalWidths: Pointer = nil; function ScriptStringGetLogicalWidths; begin if _ScriptStringGetLogicalWidths = nil then GetProcedureAddress(_ScriptStringGetLogicalWidths, Usp10DLL, 'ScriptStringGetLogicalWidths'); asm MOV ESP, EBP POP EBP JMP [_ScriptStringGetLogicalWidths] end; end; var _ScriptStringValidate: Pointer = nil; function ScriptStringValidate; begin if _ScriptStringValidate = nil then GetProcedureAddress(_ScriptStringValidate, Usp10DLL, 'ScriptStringValidate'); asm MOV ESP, EBP POP EBP JMP [_ScriptStringValidate] end; end; var _ScriptStringOut: Pointer = nil; function ScriptStringOut; begin if _ScriptStringOut = nil then GetProcedureAddress(_ScriptStringOut, Usp10DLL, 'ScriptStringOut'); asm MOV ESP, EBP POP EBP JMP [_ScriptStringOut] end; end; var _ScriptIsComplex: Pointer = nil; function ScriptIsComplex; begin if _ScriptIsComplex = nil then GetProcedureAddress(_ScriptIsComplex, Usp10DLL, 'ScriptIsComplex'); asm MOV ESP, EBP POP EBP JMP [_ScriptIsComplex] end; end; var _ScriptRecordDigitSubstitution: Pointer = nil; function ScriptRecordDigitSubstitution; begin if _ScriptRecordDigitSubstitution = nil then GetProcedureAddress(_ScriptRecordDigitSubstitution, Usp10DLL, 'ScriptRecordDigitSubstitution'); asm MOV ESP, EBP POP EBP JMP [_ScriptRecordDigitSubstitution] end; end; var _ScriptApplyDigitSubstitution: Pointer = nil; function ScriptApplyDigitSubstitution; begin if _ScriptApplyDigitSubstitution = nil then GetProcedureAddress(_ScriptApplyDigitSubstitution, Usp10DLL, 'ScriptApplyDigitSubstitution'); asm MOV ESP, EBP POP EBP JMP [_ScriptApplyDigitSubstitution] end; end; initialization Usp10DllModule := GetUsp10DllModule; Usp10IsInstalled := Usp10DllModule <> 0; finalization if Usp10DllModule <> 0 then FreeLibrary(Usp10DllModule); end.