Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
36ac341b
Commit
36ac341b
authored
Mar 13, 2008
by
Aric Stewart
Committed by
Alexandre Julliard
Mar 13, 2008
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
gdi32: Add loading and processing of GSUB table vert/vrt2 functions for proper…
gdi32: Add loading and processing of GSUB table vert/vrt2 functions for proper tategaki (vertical writing).
parent
1137f4bf
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
377 additions
and
15 deletions
+377
-15
freetype.c
dlls/gdi32/freetype.c
+377
-15
No files found.
dlls/gdi32/freetype.c
View file @
36ac341b
...
...
@@ -336,6 +336,7 @@ struct tagGdiFont {
DWORD
ntmFlags
;
FONTSIGNATURE
fs
;
GdiFont
*
base_font
;
VOID
*
GSUB_Table
;
};
typedef
struct
{
...
...
@@ -501,6 +502,105 @@ static BOOL get_glyph_index_linked(GdiFont *font, UINT c, GdiFont **linked_font,
* cga40woa.fon=cga40850.fon
*/
/* These are all structures needed for the GSUB table */
#define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
#define TATEGAKI_LOWER_BOUND 0x02F1
typedef
struct
{
DWORD
version
;
WORD
ScriptList
;
WORD
FeatureList
;
WORD
LookupList
;
}
GSUB_Header
;
typedef
struct
{
CHAR
ScriptTag
[
4
];
WORD
Script
;
}
GSUB_ScriptRecord
;
typedef
struct
{
WORD
ScriptCount
;
GSUB_ScriptRecord
ScriptRecord
[
1
];
}
GSUB_ScriptList
;
typedef
struct
{
CHAR
LangSysTag
[
4
];
WORD
LangSys
;
}
GSUB_LangSysRecord
;
typedef
struct
{
WORD
DefaultLangSys
;
WORD
LangSysCount
;
GSUB_LangSysRecord
LangSysRecord
[
1
];
}
GSUB_Script
;
typedef
struct
{
WORD
LookupOrder
;
/* Reserved */
WORD
ReqFeatureIndex
;
WORD
FeatureCount
;
WORD
FeatureIndex
[
1
];
}
GSUB_LangSys
;
typedef
struct
{
CHAR
FeatureTag
[
4
];
WORD
Feature
;
}
GSUB_FeatureRecord
;
typedef
struct
{
WORD
FeatureCount
;
GSUB_FeatureRecord
FeatureRecord
[
1
];
}
GSUB_FeatureList
;
typedef
struct
{
WORD
FeatureParams
;
/* Reserved */
WORD
LookupCount
;
WORD
LookupListIndex
[
1
];
}
GSUB_Feature
;
typedef
struct
{
WORD
LookupCount
;
WORD
Lookup
[
1
];
}
GSUB_LookupList
;
typedef
struct
{
WORD
LookupType
;
WORD
LookupFlag
;
WORD
SubTableCount
;
WORD
SubTable
[
1
];
}
GSUB_LookupTable
;
typedef
struct
{
WORD
CoverageFormat
;
WORD
GlyphCount
;
WORD
GlyphArray
[
1
];
}
GSUB_CoverageFormat1
;
typedef
struct
{
WORD
Start
;
WORD
End
;
WORD
StartCoverageIndex
;
}
GSUB_RangeRecord
;
typedef
struct
{
WORD
CoverageFormat
;
WORD
RangeCount
;
GSUB_RangeRecord
RangeRecord
[
1
];
}
GSUB_CoverageFormat2
;
typedef
struct
{
WORD
SubstFormat
;
/* = 1 */
WORD
Coverage
;
WORD
DeltaGlyphID
;
}
GSUB_SingleSubstFormat1
;
typedef
struct
{
WORD
SubstFormat
;
/* = 2 */
WORD
Coverage
;
WORD
GlyphCount
;
WORD
Substitute
[
1
];
}
GSUB_SingleSubstFormat2
;
#ifdef HAVE_CARBON_CARBON_H
static
char
*
find_cache_dir
(
void
)
{
...
...
@@ -2628,6 +2728,7 @@ static void free_font(GdiFont *font)
for
(
i
=
0
;
i
<
font
->
gmsize
;
i
++
)
HeapFree
(
GetProcessHeap
(),
0
,
font
->
gm
[
i
]);
HeapFree
(
GetProcessHeap
(),
0
,
font
->
gm
);
HeapFree
(
GetProcessHeap
(),
0
,
font
->
GSUB_Table
);
HeapFree
(
GetProcessHeap
(),
0
,
font
);
}
...
...
@@ -3321,6 +3422,17 @@ found:
ret
->
strikeout
=
lf
.
lfStrikeOut
?
0xff
:
0
;
create_child_font_list
(
ret
);
if
(
lf
.
lfFaceName
[
0
]
==
'@'
)
/* We need to try to load the GSUB table */
{
int
length
=
WineEngGetFontData
(
ret
,
GSUB_TAG
,
0
,
NULL
,
0
);
if
(
length
!=
GDI_ERROR
)
{
ret
->
GSUB_Table
=
HeapAlloc
(
GetProcessHeap
(),
0
,
length
);
WineEngGetFontData
(
ret
,
GSUB_TAG
,
0
,
ret
->
GSUB_Table
,
length
);
TRACE
(
"Loaded GSUB table of %i bytes
\n
"
,
length
);
}
}
TRACE
(
"caching: gdiFont=%p hfont=%p
\n
"
,
ret
,
hfont
);
list_add_head
(
&
gdi_font_list
,
&
ret
->
entry
);
...
...
@@ -3679,8 +3791,249 @@ static BOOL codepage_sets_default_used(UINT codepage)
}
}
/*
* GSUB Table handling functions
*/
static
INT
GSUB_is_glyph_covered
(
LPCVOID
table
,
UINT
glyph
)
{
const
GSUB_CoverageFormat1
*
cf1
;
cf1
=
(
GSUB_CoverageFormat1
*
)
table
;
if
(
GET_BE_WORD
(
cf1
->
CoverageFormat
)
==
1
)
{
int
count
=
GET_BE_WORD
(
cf1
->
GlyphCount
);
int
i
;
TRACE
(
"Coverage Format 1, %i glyphs
\n
"
,
count
);
for
(
i
=
0
;
i
<
count
;
i
++
)
if
(
glyph
==
GET_BE_WORD
(
cf1
->
GlyphArray
[
i
]))
return
i
;
return
-
1
;
}
else
if
(
GET_BE_WORD
(
cf1
->
CoverageFormat
)
==
2
)
{
const
GSUB_CoverageFormat2
*
cf2
;
int
i
;
int
count
;
cf2
=
(
GSUB_CoverageFormat2
*
)
cf1
;
count
=
GET_BE_WORD
(
cf2
->
RangeCount
);
TRACE
(
"Coverage Format 2, %i ranges
\n
"
,
count
);
for
(
i
=
0
;
i
<
count
;
i
++
)
{
if
(
glyph
<
GET_BE_WORD
(
cf2
->
RangeRecord
[
i
].
Start
))
return
-
1
;
if
((
glyph
>=
GET_BE_WORD
(
cf2
->
RangeRecord
[
i
].
Start
))
&&
(
glyph
<=
GET_BE_WORD
(
cf2
->
RangeRecord
[
i
].
End
)))
{
return
(
GET_BE_WORD
(
cf2
->
RangeRecord
[
i
].
StartCoverageIndex
)
+
glyph
-
GET_BE_WORD
(
cf2
->
RangeRecord
[
i
].
Start
));
}
return
-
1
;
}
}
else
ERR
(
"Unknown CoverageFormat %i
\n
"
,
GET_BE_WORD
(
cf1
->
CoverageFormat
));
return
-
1
;
}
static
const
GSUB_Script
*
GSUB_get_script_table
(
const
GSUB_Header
*
header
,
const
char
*
tag
)
{
const
GSUB_ScriptList
*
script
;
const
GSUB_Script
*
deflt
=
NULL
;
int
i
;
script
=
(
GSUB_ScriptList
*
)((
LPBYTE
)
header
+
GET_BE_WORD
(
header
->
ScriptList
));
TRACE
(
"%i scripts in this font
\n
"
,
GET_BE_WORD
(
script
->
ScriptCount
));
for
(
i
=
0
;
i
<
GET_BE_WORD
(
script
->
ScriptCount
);
i
++
)
{
const
GSUB_Script
*
scr
;
int
offset
;
offset
=
GET_BE_WORD
(
script
->
ScriptRecord
[
i
].
Script
);
scr
=
(
GSUB_Script
*
)((
LPBYTE
)
script
+
offset
);
if
(
strncmp
(
script
->
ScriptRecord
[
i
].
ScriptTag
,
tag
,
4
)
==
0
)
return
scr
;
if
(
strncmp
(
script
->
ScriptRecord
[
i
].
ScriptTag
,
"dflt"
,
4
)
==
0
)
deflt
=
scr
;
}
return
deflt
;
}
static
const
GSUB_LangSys
*
GSUB_get_lang_table
(
const
GSUB_Script
*
script
,
const
char
*
tag
)
{
int
i
;
int
offset
;
const
GSUB_LangSys
*
Lang
;
TRACE
(
"Deflang %x, LangCount %i
\n
"
,
GET_BE_WORD
(
script
->
DefaultLangSys
),
GET_BE_WORD
(
script
->
LangSysCount
));
for
(
i
=
0
;
i
<
GET_BE_WORD
(
script
->
LangSysCount
)
;
i
++
)
{
offset
=
GET_BE_WORD
(
script
->
LangSysRecord
[
i
].
LangSys
);
Lang
=
(
GSUB_LangSys
*
)((
LPBYTE
)
script
+
offset
);
if
(
strncmp
(
script
->
LangSysRecord
[
i
].
LangSysTag
,
tag
,
4
)
==
0
)
return
Lang
;
}
offset
=
GET_BE_WORD
(
script
->
DefaultLangSys
);
if
(
offset
)
{
Lang
=
(
GSUB_LangSys
*
)((
LPBYTE
)
script
+
offset
);
return
Lang
;
}
return
NULL
;
}
static
const
GSUB_Feature
*
GSUB_get_feature
(
const
GSUB_Header
*
header
,
const
GSUB_LangSys
*
lang
,
const
char
*
tag
)
{
int
i
;
const
GSUB_FeatureList
*
feature
;
feature
=
(
GSUB_FeatureList
*
)((
LPBYTE
)
header
+
GET_BE_WORD
(
header
->
FeatureList
));
TRACE
(
"%i features
\n
"
,
GET_BE_WORD
(
lang
->
FeatureCount
));
for
(
i
=
0
;
i
<
GET_BE_WORD
(
lang
->
FeatureCount
);
i
++
)
{
int
index
=
GET_BE_WORD
(
lang
->
FeatureIndex
[
i
]);
if
(
strncmp
(
feature
->
FeatureRecord
[
index
].
FeatureTag
,
tag
,
4
)
==
0
)
{
const
GSUB_Feature
*
feat
;
feat
=
(
GSUB_Feature
*
)((
LPBYTE
)
feature
+
GET_BE_WORD
(
feature
->
FeatureRecord
[
index
].
Feature
));
return
feat
;
}
}
return
NULL
;
}
static
FT_UInt
GSUB_apply_feature
(
const
GSUB_Header
*
header
,
const
GSUB_Feature
*
feature
,
UINT
glyph
)
{
int
i
;
int
offset
;
const
GSUB_LookupList
*
lookup
;
lookup
=
(
GSUB_LookupList
*
)((
LPBYTE
)
header
+
GET_BE_WORD
(
header
->
LookupList
));
TRACE
(
"%i lookups
\n
"
,
GET_BE_WORD
(
feature
->
LookupCount
));
for
(
i
=
0
;
i
<
GET_BE_WORD
(
feature
->
LookupCount
);
i
++
)
{
const
GSUB_LookupTable
*
look
;
offset
=
GET_BE_WORD
(
lookup
->
Lookup
[
GET_BE_WORD
(
feature
->
LookupListIndex
[
i
])]);
look
=
(
GSUB_LookupTable
*
)((
LPBYTE
)
lookup
+
offset
);
TRACE
(
"type %i, flag %x, subtables %i
\n
"
,
GET_BE_WORD
(
look
->
LookupType
),
GET_BE_WORD
(
look
->
LookupFlag
),
GET_BE_WORD
(
look
->
SubTableCount
));
if
(
GET_BE_WORD
(
look
->
LookupType
)
!=
1
)
FIXME
(
"We only handle SubType 1
\n
"
);
else
{
int
j
;
for
(
j
=
0
;
j
<
GET_BE_WORD
(
look
->
SubTableCount
);
j
++
)
{
const
GSUB_SingleSubstFormat1
*
ssf1
;
offset
=
GET_BE_WORD
(
look
->
SubTable
[
j
]);
ssf1
=
(
GSUB_SingleSubstFormat1
*
)((
LPBYTE
)
look
+
offset
);
if
(
GET_BE_WORD
(
ssf1
->
SubstFormat
)
==
1
)
{
int
offset
=
GET_BE_WORD
(
ssf1
->
Coverage
);
TRACE
(
" subtype 1, delta %i
\n
"
,
GET_BE_WORD
(
ssf1
->
DeltaGlyphID
));
if
(
GSUB_is_glyph_covered
((
LPBYTE
)
ssf1
+
offset
,
glyph
)
!=
-
1
)
{
TRACE
(
" Glyph 0x%x ->"
,
glyph
);
glyph
+=
GET_BE_WORD
(
ssf1
->
DeltaGlyphID
);
TRACE
(
" 0x%x
\n
"
,
glyph
);
}
}
else
{
const
GSUB_SingleSubstFormat2
*
ssf2
;
INT
index
;
INT
offset
;
ssf2
=
(
GSUB_SingleSubstFormat2
*
)
ssf1
;
offset
=
GET_BE_WORD
(
ssf1
->
Coverage
);
TRACE
(
" subtype 2, glyph count %i
\n
"
,
GET_BE_WORD
(
ssf2
->
GlyphCount
));
index
=
GSUB_is_glyph_covered
((
LPBYTE
)
ssf2
+
offset
,
glyph
);
TRACE
(
" Coverage index %i
\n
"
,
index
);
if
(
index
!=
-
1
)
{
TRACE
(
" Glyph is 0x%x ->"
,
glyph
);
glyph
=
GET_BE_WORD
(
ssf2
->
Substitute
[
index
]);
TRACE
(
"0x%x
\n
"
,
glyph
);
}
}
}
}
}
return
glyph
;
}
static
const
char
*
get_opentype_script
(
const
GdiFont
*
font
)
{
/*
* I am not sure if this is the correct way to generate our script tag
*/
switch
(
font
->
charset
)
{
case
ANSI_CHARSET
:
return
"latn"
;
case
BALTIC_CHARSET
:
return
"latn"
;
/* ?? */
case
CHINESEBIG5_CHARSET
:
return
"hani"
;
case
EASTEUROPE_CHARSET
:
return
"latn"
;
/* ?? */
case
GB2312_CHARSET
:
return
"hani"
;
case
GREEK_CHARSET
:
return
"grek"
;
case
HANGUL_CHARSET
:
return
"hang"
;
case
RUSSIAN_CHARSET
:
return
"cyrl"
;
case
SHIFTJIS_CHARSET
:
return
"kana"
;
case
TURKISH_CHARSET
:
return
"latn"
;
/* ?? */
case
VIETNAMESE_CHARSET
:
return
"latn"
;
case
JOHAB_CHARSET
:
return
"latn"
;
/* ?? */
case
ARABIC_CHARSET
:
return
"arab"
;
case
HEBREW_CHARSET
:
return
"hebr"
;
case
THAI_CHARSET
:
return
"thai"
;
default:
return
"latn"
;
}
}
static
FT_UInt
get_GSUB_vert_glyph
(
const
GdiFont
*
font
,
UINT
glyph
)
{
const
GSUB_Header
*
header
;
const
GSUB_Script
*
script
;
const
GSUB_LangSys
*
language
;
const
GSUB_Feature
*
feature
;
if
(
!
font
->
GSUB_Table
)
return
glyph
;
header
=
font
->
GSUB_Table
;
script
=
GSUB_get_script_table
(
header
,
get_opentype_script
(
font
));
if
(
!
script
)
{
TRACE
(
"Script not found
\n
"
);
return
glyph
;
}
language
=
GSUB_get_lang_table
(
script
,
"xxxx"
);
/* Need to get Lang tag */
if
(
!
language
)
{
TRACE
(
"Language not found
\n
"
);
return
glyph
;
}
feature
=
GSUB_get_feature
(
header
,
language
,
"vrt2"
);
if
(
!
feature
)
feature
=
GSUB_get_feature
(
header
,
language
,
"vert"
);
if
(
!
feature
)
{
TRACE
(
"vrt2/vert feature not found
\n
"
);
return
glyph
;
}
return
GSUB_apply_feature
(
header
,
feature
,
glyph
);
}
static
FT_UInt
get_glyph_index
(
const
GdiFont
*
font
,
UINT
glyph
)
{
FT_UInt
glyphId
;
if
(
font
->
ft_face
->
charmap
->
encoding
==
FT_ENCODING_NONE
)
{
WCHAR
wc
=
(
WCHAR
)
glyph
;
BOOL
default_used
;
...
...
@@ -3696,12 +4049,13 @@ static FT_UInt get_glyph_index(const GdiFont *font, UINT glyph)
else
ret
=
pFT_Get_Char_Index
(
font
->
ft_face
,
(
unsigned
char
)
buf
);
TRACE
(
"%04x (%02x) -> ret %d def_used %d
\n
"
,
glyph
,
buf
,
ret
,
default_used
);
return
ret
;
return
get_GSUB_vert_glyph
(
font
,
ret
)
;
}
if
(
font
->
charset
==
SYMBOL_CHARSET
&&
glyph
<
0x100
)
glyph
=
glyph
+
0xf000
;
return
pFT_Get_Char_Index
(
font
->
ft_face
,
glyph
);
glyphId
=
pFT_Get_Char_Index
(
font
->
ft_face
,
glyph
);
return
get_GSUB_vert_glyph
(
font
,
glyphId
);
}
/*************************************************************
...
...
@@ -3759,6 +4113,8 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
float
widthRatio
=
1
.
0
;
FT_Matrix
transMat
=
identityMat
;
BOOL
needsTransform
=
FALSE
;
BOOL
tategaki
=
(
font
->
GSUB_Table
!=
NULL
);
UINT
original_index
;
TRACE
(
"%p, %04x, %08x, %p, %08x, %p, %p
\n
"
,
font
,
glyph
,
format
,
lpgm
,
...
...
@@ -3767,27 +4123,33 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
EnterCriticalSection
(
&
freetype_cs
);
if
(
format
&
GGO_GLYPH_INDEX
)
{
glyph_index
=
glyph
;
glyph_index
=
get_GSUB_vert_glyph
(
incoming_font
,
glyph
);
original_index
=
glyph
;
format
&=
~
GGO_GLYPH_INDEX
;
}
else
{
get_glyph_index_linked
(
incoming_font
,
glyph
,
&
font
,
&
glyph_index
);
ft_face
=
font
->
ft_face
;
original_index
=
glyph_index
;
}
if
(
glyph_index
>=
font
->
gmsize
*
GM_BLOCK_SIZE
)
{
font
->
gmsize
=
(
glyph_index
/
GM_BLOCK_SIZE
+
1
);
/* tategaki never appears to happen to lower glyph index */
if
(
glyph_index
<
TATEGAKI_LOWER_BOUND
)
tategaki
=
FALSE
;
if
(
original_index
>=
font
->
gmsize
*
GM_BLOCK_SIZE
)
{
font
->
gmsize
=
(
original_index
/
GM_BLOCK_SIZE
+
1
);
font
->
gm
=
HeapReAlloc
(
GetProcessHeap
(),
HEAP_ZERO_MEMORY
,
font
->
gm
,
font
->
gmsize
*
sizeof
(
GM
*
));
}
else
{
if
(
format
==
GGO_METRICS
&&
font
->
gm
[
glyph_index
/
GM_BLOCK_SIZE
]
!=
NULL
&&
FONT_GM
(
font
,
glyph
_index
)
->
init
)
{
*
lpgm
=
FONT_GM
(
font
,
glyph
_index
)
->
gm
;
if
(
format
==
GGO_METRICS
&&
font
->
gm
[
original_index
/
GM_BLOCK_SIZE
]
!=
NULL
&&
FONT_GM
(
font
,
original
_index
)
->
init
)
{
*
lpgm
=
FONT_GM
(
font
,
original
_index
)
->
gm
;
LeaveCriticalSection
(
&
freetype_cs
);
return
1
;
/* FIXME */
}
}
if
(
!
font
->
gm
[
glyph
_index
/
GM_BLOCK_SIZE
])
font
->
gm
[
glyph
_index
/
GM_BLOCK_SIZE
]
=
HeapAlloc
(
GetProcessHeap
(),
HEAP_ZERO_MEMORY
,
sizeof
(
GM
)
*
GM_BLOCK_SIZE
);
if
(
!
font
->
gm
[
original
_index
/
GM_BLOCK_SIZE
])
font
->
gm
[
original
_index
/
GM_BLOCK_SIZE
]
=
HeapAlloc
(
GetProcessHeap
(),
HEAP_ZERO_MEMORY
,
sizeof
(
GM
)
*
GM_BLOCK_SIZE
);
if
(
font
->
orientation
||
(
format
!=
GGO_METRICS
&&
format
!=
GGO_BITMAP
&&
format
!=
WINE_GGO_GRAY16_BITMAP
)
||
lpmat
)
load_flags
|=
FT_LOAD_NO_BITMAP
;
...
...
@@ -3841,7 +4203,7 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
}
/* Rotation transform */
if
(
font
->
orientation
)
{
if
(
font
->
orientation
&&
!
tategaki
)
{
FT_Matrix
rotationMat
;
FT_Vector
vecAngle
;
angle
=
FT_FixedFromFloat
((
float
)
font
->
orientation
/
10
.
0
);
...
...
@@ -3913,11 +4275,11 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
if
(
format
==
GGO_METRICS
||
format
==
GGO_BITMAP
||
format
==
WINE_GGO_GRAY16_BITMAP
)
{
FONT_GM
(
font
,
glyph
_index
)
->
gm
=
*
lpgm
;
FONT_GM
(
font
,
glyph
_index
)
->
adv
=
adv
;
FONT_GM
(
font
,
glyph
_index
)
->
lsb
=
lsb
;
FONT_GM
(
font
,
glyph
_index
)
->
bbx
=
bbx
;
FONT_GM
(
font
,
glyph
_index
)
->
init
=
TRUE
;
FONT_GM
(
font
,
original
_index
)
->
gm
=
*
lpgm
;
FONT_GM
(
font
,
original
_index
)
->
adv
=
adv
;
FONT_GM
(
font
,
original
_index
)
->
lsb
=
lsb
;
FONT_GM
(
font
,
original
_index
)
->
bbx
=
bbx
;
FONT_GM
(
font
,
original
_index
)
->
init
=
TRUE
;
}
if
(
format
==
GGO_METRICS
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment