Rework opentype interfaces and other changes to make GPOS work for Arabic.
Sun Feb 29 09:25:13 2004 Owen Taylor <otaylor@redhat.com> Rework opentype interfaces and other changes to make GPOS work for Arabic. (Most of #117282, #121060) * pango/opentype/otlbuffer.[ch]: OTL_Buffer that acts as a replacement for the separate GSUB and GPOS string structures and hides many of the internal details. * pango/opentype/ftxgsub.[ch] pango/opentype/ftxgpos.[ch]: Adapt to OTL_Buffer. * pango/opentype/ftxgpos.c: Redo handling of cursive chains so that it actually works. * pango/pango-ot.h pango/opentype/pango-ot-buffer.c: Pango wrapper around OTL_Buffer. * pango/pango-ot.h pango/pango-ot-ruleset.c pango/pango-ot-buffer.c: Split pango_ot_ruleset_shape() into pango_ot_ruleset_substitute(), pango_ot_ruleset_position(), make them act on PangoOTBuffer, add a separate pango_ot_buffer_output() which does the default positioning and writes to a PangoGlyphString. * modules/arabic/arabic-fc.c modules/indic/indic-fc.c modules/indic/mprefixups.[ch]: Adapt to new OpenType interfaces; add GPOS features for Arabic. * pango/opentype/pango-ot-info.c: Don't derive class information from Unicode properties for Arabic presentation forms, let the shaping process derive the properties.
This commit is contained in:
parent
d670ddf991
commit
a7e096c5de
|
@ -30,6 +30,9 @@ libpango_ot_la_SOURCES = \
|
||||||
ftxgpos.h \
|
ftxgpos.h \
|
||||||
ftxgsub.c \
|
ftxgsub.c \
|
||||||
ftxgsub.h \
|
ftxgsub.h \
|
||||||
|
otlbuffer.c \
|
||||||
|
otlbuffer.h \
|
||||||
|
pango-ot-buffer.c \
|
||||||
pango-ot-info.c \
|
pango-ot-info.c \
|
||||||
pango-ot-private.h \
|
pango-ot-private.h \
|
||||||
pango-ot-ruleset.c
|
pango-ot-ruleset.c
|
||||||
|
|
|
@ -761,7 +761,7 @@
|
||||||
|
|
||||||
if ( glyphID < gcrr[index].Start )
|
if ( glyphID < gcrr[index].Start )
|
||||||
{
|
{
|
||||||
array_index = 0;
|
array_index = index;
|
||||||
if ( index == 0 )
|
if ( index == 0 )
|
||||||
glyph_index = glyphID;
|
glyph_index = glyphID;
|
||||||
else
|
else
|
||||||
|
@ -1129,7 +1129,7 @@
|
||||||
|
|
||||||
if ( glyphID < gcrr[index].Start )
|
if ( glyphID < gcrr[index].Start )
|
||||||
{
|
{
|
||||||
array_index = 0;
|
array_index = index;
|
||||||
if ( index == 0 )
|
if ( index == 0 )
|
||||||
glyph_index = glyphID;
|
glyph_index = glyphID;
|
||||||
else
|
else
|
||||||
|
|
573
src/ftxgpos.c
573
src/ftxgpos.c
File diff suppressed because it is too large
Load Diff
|
@ -758,26 +758,6 @@ extern "C" {
|
||||||
typedef union TTO_GPOS_SubTable_ TTO_GPOS_SubTable;
|
typedef union TTO_GPOS_SubTable_ TTO_GPOS_SubTable;
|
||||||
|
|
||||||
|
|
||||||
/* This `string object' is much simpler compared to TTO_GSUB_String.
|
|
||||||
A call to TTO_GPOS_Apply_String() will allocate it. */
|
|
||||||
|
|
||||||
struct TTO_GPOS_Data_
|
|
||||||
{
|
|
||||||
FT_Pos x_pos;
|
|
||||||
FT_Pos y_pos;
|
|
||||||
FT_Pos x_advance;
|
|
||||||
FT_Pos y_advance;
|
|
||||||
FT_UShort back; /* number of glyphs to go back
|
|
||||||
for drawing current glyph */
|
|
||||||
FT_Bool new_advance; /* if set, the advance width values are
|
|
||||||
absolute, i.e., they won't be
|
|
||||||
added to the original glyph's value
|
|
||||||
but rather replace them. */
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct TTO_GPOS_Data_ TTO_GPOS_Data;
|
|
||||||
|
|
||||||
|
|
||||||
/* finally, the GPOS API */
|
/* finally, the GPOS API */
|
||||||
|
|
||||||
/* EXPORT_DEF
|
/* EXPORT_DEF
|
||||||
|
@ -844,8 +824,7 @@ extern "C" {
|
||||||
FT_Error TT_GPOS_Apply_String( FT_Face face,
|
FT_Error TT_GPOS_Apply_String( FT_Face face,
|
||||||
TTO_GPOSHeader* gpos,
|
TTO_GPOSHeader* gpos,
|
||||||
FT_UShort load_flags,
|
FT_UShort load_flags,
|
||||||
TTO_GSUB_String* in,
|
OTL_Buffer buffer,
|
||||||
TTO_GPOS_Data** out,
|
|
||||||
FT_Bool dvi,
|
FT_Bool dvi,
|
||||||
FT_Bool r2l );
|
FT_Bool r2l );
|
||||||
|
|
||||||
|
|
705
src/ftxgsub.c
705
src/ftxgsub.c
File diff suppressed because it is too large
Load Diff
|
@ -504,23 +504,6 @@ extern "C" {
|
||||||
TT_Add_String() will also handle allocation; you should use
|
TT_Add_String() will also handle allocation; you should use
|
||||||
free() in case you want to destroy the arrays in the object. */
|
free() in case you want to destroy the arrays in the object. */
|
||||||
|
|
||||||
struct TTO_GSUB_String_
|
|
||||||
{
|
|
||||||
FT_Memory memory;
|
|
||||||
|
|
||||||
FT_ULong length;
|
|
||||||
FT_ULong pos;
|
|
||||||
FT_ULong allocated;
|
|
||||||
FT_UShort* string;
|
|
||||||
FT_UShort* properties;
|
|
||||||
FT_UShort* components;
|
|
||||||
FT_UShort max_ligID;
|
|
||||||
FT_UShort* ligIDs;
|
|
||||||
FT_Int* logClusters;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct TTO_GSUB_String_ TTO_GSUB_String;
|
|
||||||
|
|
||||||
|
|
||||||
/* finally, the GSUB API */
|
/* finally, the GSUB API */
|
||||||
|
|
||||||
|
@ -577,31 +560,10 @@ extern "C" {
|
||||||
TTO_AltFunction altfunc,
|
TTO_AltFunction altfunc,
|
||||||
void* data );
|
void* data );
|
||||||
|
|
||||||
EXPORT_DEF
|
|
||||||
FT_Error TT_GSUB_String_New( FT_Memory memory,
|
|
||||||
TTO_GSUB_String **result );
|
|
||||||
|
|
||||||
EXPORT_DEF
|
|
||||||
FT_Error TT_GSUB_String_Set_Length( TTO_GSUB_String *str,
|
|
||||||
FT_ULong new_length);
|
|
||||||
|
|
||||||
EXPORT_DEF
|
|
||||||
FT_Error TT_GSUB_String_Done( TTO_GSUB_String *str );
|
|
||||||
|
|
||||||
|
|
||||||
EXPORT_DEF
|
EXPORT_DEF
|
||||||
FT_Error TT_GSUB_Apply_String( TTO_GSUBHeader* gsub,
|
FT_Error TT_GSUB_Apply_String( TTO_GSUBHeader* gsub,
|
||||||
TTO_GSUB_String* in,
|
OTL_Buffer buffer );
|
||||||
TTO_GSUB_String* out );
|
|
||||||
|
|
||||||
EXPORT_DEF
|
|
||||||
FT_Error TT_GSUB_Add_String( TTO_GSUB_String* in,
|
|
||||||
FT_UShort num_in,
|
|
||||||
TTO_GSUB_String* out,
|
|
||||||
FT_UShort num_out,
|
|
||||||
FT_UShort* glyph_data,
|
|
||||||
FT_UShort component,
|
|
||||||
FT_UShort ligID );
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -280,6 +280,7 @@ extern "C" {
|
||||||
typedef struct TTO_Device_ TTO_Device;
|
typedef struct TTO_Device_ TTO_Device;
|
||||||
|
|
||||||
|
|
||||||
|
#include "otlbuffer.h"
|
||||||
#include "ftxgdef.h"
|
#include "ftxgdef.h"
|
||||||
#include "ftxgsub.h"
|
#include "ftxgsub.h"
|
||||||
#include "ftxgpos.h"
|
#include "ftxgpos.h"
|
||||||
|
|
|
@ -0,0 +1,213 @@
|
||||||
|
/* otlbuffer.c: Buffer of glyphs for substitution/positioning
|
||||||
|
*
|
||||||
|
* Copyright 2004 Red Hat Software
|
||||||
|
*
|
||||||
|
* Portions Copyright 1996-2000 by
|
||||||
|
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||||
|
*
|
||||||
|
* This file is part of the FreeType project, and may only be used
|
||||||
|
* modified and distributed under the terms of the FreeType project
|
||||||
|
* license, LICENSE.TXT. By continuing to use, modify, or distribute
|
||||||
|
* this file you indicate that you have read the license and
|
||||||
|
* understand and accept it fully.
|
||||||
|
*/
|
||||||
|
#include <otlbuffer.h>
|
||||||
|
|
||||||
|
#include FT_INTERNAL_MEMORY_H
|
||||||
|
|
||||||
|
static FT_Error
|
||||||
|
otl_buffer_ensure( OTL_Buffer buffer,
|
||||||
|
FT_ULong size )
|
||||||
|
{
|
||||||
|
FT_Memory memory = buffer->memory;
|
||||||
|
FT_ULong new_allocated = buffer->allocated;
|
||||||
|
|
||||||
|
if (size > new_allocated)
|
||||||
|
{
|
||||||
|
FT_Error error;
|
||||||
|
|
||||||
|
while (size > new_allocated)
|
||||||
|
new_allocated += (new_allocated >> 1) + 8;
|
||||||
|
|
||||||
|
if ( FT_REALLOC_ARRAY( buffer->in_string, buffer->allocated, new_allocated, OTL_GlyphItemRec ) )
|
||||||
|
return error;
|
||||||
|
if ( FT_REALLOC_ARRAY( buffer->out_string, buffer->allocated, new_allocated, OTL_GlyphItemRec ) )
|
||||||
|
return error;
|
||||||
|
if ( FT_REALLOC_ARRAY( buffer->positions, buffer->allocated, new_allocated, OTL_PositionRec ) )
|
||||||
|
return error;
|
||||||
|
|
||||||
|
buffer->allocated = new_allocated;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FT_Err_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Error
|
||||||
|
otl_buffer_new( FT_Memory memory,
|
||||||
|
OTL_Buffer *buffer )
|
||||||
|
{
|
||||||
|
FT_Error error;
|
||||||
|
|
||||||
|
if ( FT_ALLOC( *buffer, sizeof( OTL_BufferRec ) ) )
|
||||||
|
return error;
|
||||||
|
|
||||||
|
(*buffer)->memory = memory;
|
||||||
|
(*buffer)->in_length = 0;
|
||||||
|
(*buffer)->out_length = 0;
|
||||||
|
(*buffer)->allocated = 0;
|
||||||
|
(*buffer)->in_pos = 0;
|
||||||
|
(*buffer)->out_pos = 0;
|
||||||
|
|
||||||
|
(*buffer)->in_string = NULL;
|
||||||
|
(*buffer)->out_string = NULL;
|
||||||
|
(*buffer)->positions = NULL;
|
||||||
|
(*buffer)->max_ligID = 0;
|
||||||
|
|
||||||
|
return FT_Err_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Error
|
||||||
|
otl_buffer_swap( OTL_Buffer buffer )
|
||||||
|
{
|
||||||
|
OTL_GlyphItem tmp_string;
|
||||||
|
|
||||||
|
tmp_string = buffer->in_string;
|
||||||
|
buffer->in_string = buffer->out_string;
|
||||||
|
buffer->out_string = tmp_string;
|
||||||
|
|
||||||
|
buffer->in_length = buffer->out_length;
|
||||||
|
buffer->out_length = 0;
|
||||||
|
|
||||||
|
buffer->in_pos = 0;
|
||||||
|
buffer->out_pos = 0;
|
||||||
|
|
||||||
|
return FT_Err_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Error
|
||||||
|
otl_buffer_free( OTL_Buffer buffer )
|
||||||
|
{
|
||||||
|
FT_Memory memory = buffer->memory;
|
||||||
|
|
||||||
|
FT_FREE( buffer->in_string );
|
||||||
|
FT_FREE( buffer->out_string );
|
||||||
|
FT_FREE( buffer );
|
||||||
|
|
||||||
|
return FT_Err_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Error
|
||||||
|
otl_buffer_clear( OTL_Buffer buffer )
|
||||||
|
{
|
||||||
|
buffer->in_length = 0;
|
||||||
|
buffer->out_length = 0;
|
||||||
|
buffer->in_pos = 0;
|
||||||
|
buffer->out_pos = 0;
|
||||||
|
|
||||||
|
return FT_Err_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Error
|
||||||
|
otl_buffer_add_glyph( OTL_Buffer buffer,
|
||||||
|
FT_UInt glyph_index,
|
||||||
|
FT_UInt properties,
|
||||||
|
FT_UInt cluster )
|
||||||
|
{
|
||||||
|
FT_Error error;
|
||||||
|
OTL_GlyphItem glyph;
|
||||||
|
|
||||||
|
error = otl_buffer_ensure( buffer, buffer->in_length + 1 );
|
||||||
|
if ( error != FT_Err_Ok )
|
||||||
|
return error;
|
||||||
|
|
||||||
|
glyph = &buffer->in_string[buffer->in_length];
|
||||||
|
glyph->gindex = glyph_index;
|
||||||
|
glyph->properties = properties;
|
||||||
|
glyph->cluster = cluster;
|
||||||
|
glyph->component = 0;
|
||||||
|
glyph->ligID = 0;
|
||||||
|
|
||||||
|
buffer->in_length++;
|
||||||
|
|
||||||
|
return FT_Err_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The following function copies `num_out' elements from `glyph_data'
|
||||||
|
to `buffer->out_string', advancing the in array pointer in the structure
|
||||||
|
by `num_in' elements, and the out array pointer by `num_out' elements.
|
||||||
|
Finally, it sets the `length' field of `out' equal to
|
||||||
|
`pos' of the `out' structure.
|
||||||
|
|
||||||
|
If `component' is 0xFFFF, the component value from buffer->in_pos
|
||||||
|
will copied `num_out' times, otherwise `component' itself will
|
||||||
|
be used to fill the `component' fields.
|
||||||
|
|
||||||
|
If `ligID' is 0xFFFF, the ligID value from buffer->in_pos
|
||||||
|
will copied `num_out' times, otherwise `ligID' itself will
|
||||||
|
be used to fill the `ligID' fields.
|
||||||
|
|
||||||
|
The properties for all replacement glyphs are taken
|
||||||
|
from the glyph at position `buffer->in_pos'.
|
||||||
|
|
||||||
|
The cluster value for the glyph at position buffer->in_pos is used
|
||||||
|
for all replacement glyphs */
|
||||||
|
FT_Error
|
||||||
|
otl_buffer_add_output_glyphs( OTL_Buffer buffer,
|
||||||
|
FT_UShort num_in,
|
||||||
|
FT_UShort num_out,
|
||||||
|
FT_UShort *glyph_data,
|
||||||
|
FT_UShort component,
|
||||||
|
FT_UShort ligID )
|
||||||
|
{
|
||||||
|
FT_Error error;
|
||||||
|
FT_UShort i;
|
||||||
|
FT_UInt properties;
|
||||||
|
FT_UInt cluster;
|
||||||
|
|
||||||
|
error = otl_buffer_ensure( buffer, buffer->out_pos + num_out );
|
||||||
|
if ( error != FT_Err_Ok )
|
||||||
|
return error;
|
||||||
|
|
||||||
|
properties = buffer->in_string[buffer->in_pos].properties;
|
||||||
|
cluster = buffer->in_string[buffer->in_pos].cluster;
|
||||||
|
if ( component == 0xFFFF )
|
||||||
|
component = buffer->in_string[buffer->in_pos].component;
|
||||||
|
if ( ligID == 0xFFFF )
|
||||||
|
ligID = buffer->in_string[buffer->in_pos].ligID;
|
||||||
|
|
||||||
|
for ( i = 0; i < num_out; i++ )
|
||||||
|
{
|
||||||
|
OTL_GlyphItem item = &buffer->out_string[buffer->out_pos + i];
|
||||||
|
|
||||||
|
item->gindex = glyph_data[i];
|
||||||
|
item->properties = properties;
|
||||||
|
item->cluster = cluster;
|
||||||
|
item->component = component;
|
||||||
|
item->ligID = ligID;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer->in_pos += num_in;
|
||||||
|
buffer->out_pos += num_out;
|
||||||
|
|
||||||
|
buffer->out_length = buffer->out_pos;
|
||||||
|
|
||||||
|
return FT_Err_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Error
|
||||||
|
otl_buffer_add_output_glyph( OTL_Buffer buffer,
|
||||||
|
FT_UInt glyph_index,
|
||||||
|
FT_UShort component,
|
||||||
|
FT_UShort ligID )
|
||||||
|
{
|
||||||
|
FT_UShort glyph_data = glyph_index;
|
||||||
|
|
||||||
|
return otl_buffer_add_output_glyphs ( buffer, 1, 1,
|
||||||
|
&glyph_data, component, ligID );
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_UShort
|
||||||
|
otl_buffer_allocate_ligid( OTL_Buffer buffer )
|
||||||
|
{
|
||||||
|
return buffer->max_ligID++;
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
/* otlbuffer.h: Buffer of glyphs for substitution/positioning
|
||||||
|
*
|
||||||
|
* Copyrigh 2004 Red Hat Software
|
||||||
|
*
|
||||||
|
* Portions Copyright 1996-2000 by
|
||||||
|
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||||
|
*
|
||||||
|
* This file is part of the FreeType project, and may only be used
|
||||||
|
* modified and distributed under the terms of the FreeType project
|
||||||
|
* license, LICENSE.TXT. By continuing to use, modify, or distribute
|
||||||
|
* this file you indicate that you have read the license and
|
||||||
|
* understand and accept it fully.
|
||||||
|
*/
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
typedef struct OTL_GlyphItemRec_ {
|
||||||
|
FT_UInt gindex;
|
||||||
|
FT_UInt properties;
|
||||||
|
FT_UInt cluster;
|
||||||
|
FT_UShort component;
|
||||||
|
FT_UShort ligID;
|
||||||
|
} OTL_GlyphItemRec, *OTL_GlyphItem;
|
||||||
|
|
||||||
|
typedef struct OTL_PositionRec_ {
|
||||||
|
FT_Pos x_pos;
|
||||||
|
FT_Pos y_pos;
|
||||||
|
FT_Pos x_advance;
|
||||||
|
FT_Pos y_advance;
|
||||||
|
FT_UShort back; /* number of glyphs to go back
|
||||||
|
for drawing current glyph */
|
||||||
|
FT_Bool new_advance; /* if set, the advance width values are
|
||||||
|
absolute, i.e., they won't be
|
||||||
|
added to the original glyph's value
|
||||||
|
but rather replace them. */
|
||||||
|
FT_Short cursive_chain; /* character to which this connects,
|
||||||
|
may be positive or negative; used
|
||||||
|
only internally */
|
||||||
|
} OTL_PositionRec, *OTL_Position;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct OTL_BufferRec_{
|
||||||
|
FT_Memory memory;
|
||||||
|
FT_ULong allocated;
|
||||||
|
|
||||||
|
FT_ULong in_length;
|
||||||
|
FT_ULong out_length;
|
||||||
|
FT_ULong in_pos;
|
||||||
|
FT_ULong out_pos;
|
||||||
|
|
||||||
|
OTL_GlyphItem in_string;
|
||||||
|
OTL_GlyphItem out_string;
|
||||||
|
OTL_Position positions;
|
||||||
|
FT_UShort max_ligID;
|
||||||
|
} OTL_BufferRec, *OTL_Buffer;
|
||||||
|
|
||||||
|
FT_Error
|
||||||
|
otl_buffer_new( FT_Memory memory,
|
||||||
|
OTL_Buffer *buffer );
|
||||||
|
|
||||||
|
FT_Error
|
||||||
|
otl_buffer_swap( OTL_Buffer buffer );
|
||||||
|
|
||||||
|
FT_Error
|
||||||
|
otl_buffer_free( OTL_Buffer buffer );
|
||||||
|
|
||||||
|
FT_Error
|
||||||
|
otl_buffer_clear( OTL_Buffer buffer );
|
||||||
|
|
||||||
|
FT_Error
|
||||||
|
otl_buffer_add_glyph( OTL_Buffer buffer,
|
||||||
|
FT_UInt glyph_index,
|
||||||
|
FT_UInt properties,
|
||||||
|
FT_UInt cluster );
|
||||||
|
|
||||||
|
FT_Error
|
||||||
|
otl_buffer_add_output_glyphs( OTL_Buffer buffer,
|
||||||
|
FT_UShort num_in,
|
||||||
|
FT_UShort num_out,
|
||||||
|
FT_UShort *glyph_data,
|
||||||
|
FT_UShort component,
|
||||||
|
FT_UShort ligID );
|
||||||
|
|
||||||
|
FT_Error
|
||||||
|
otl_buffer_add_output_glyph ( OTL_Buffer buffer,
|
||||||
|
FT_UInt glyph_index,
|
||||||
|
FT_UShort component,
|
||||||
|
FT_UShort ligID );
|
||||||
|
|
||||||
|
FT_UShort
|
||||||
|
otl_buffer_allocate_ligid( OTL_Buffer buffer );
|
||||||
|
|
||||||
|
G_END_DECLS
|
|
@ -145,6 +145,7 @@ add_features (TTO_GSUB gsub)
|
||||||
maybe_add_feature (gsub, script_index, FT_MAKE_TAG ('l', 'i', 'g', 'a'), L);
|
maybe_add_feature (gsub, script_index, FT_MAKE_TAG ('l', 'i', 'g', 'a'), L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
void
|
void
|
||||||
dump_string (TTO_GSUB_String *str)
|
dump_string (TTO_GSUB_String *str)
|
||||||
{
|
{
|
||||||
|
@ -203,6 +204,7 @@ try_string (FT_Library library,
|
||||||
if ((error = TT_GSUB_String_Done (out_str)))
|
if ((error = TT_GSUB_String_Done (out_str)))
|
||||||
croak ("TT_GSUB_String_New", error);
|
croak ("TT_GSUB_String_New", error);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char **argv)
|
main (int argc, char **argv)
|
||||||
|
|
|
@ -0,0 +1,265 @@
|
||||||
|
/* Pango
|
||||||
|
* pango-ot-buffer.c: Buffer of glyphs for shaping/positioning
|
||||||
|
*
|
||||||
|
* Copyright (C) 2004 Red Hat Software
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pango-ot-private.h"
|
||||||
|
|
||||||
|
#define PANGO_SCALE_26_6 (PANGO_SCALE / (1<<6))
|
||||||
|
#define PANGO_UNITS_26_6(d) (PANGO_SCALE_26_6 * (d))
|
||||||
|
|
||||||
|
PangoOTBuffer *
|
||||||
|
pango_ot_buffer_new (PangoFcFont *font)
|
||||||
|
{
|
||||||
|
/* We lock the font here immediately for the silly reason
|
||||||
|
* of getting the FT_Memory; otherwise we'd have to
|
||||||
|
* add a new operation to PangoFcFontmap; callers will
|
||||||
|
* probably already have the font locked, however,
|
||||||
|
* so there is little performance penalty.
|
||||||
|
*/
|
||||||
|
PangoOTBuffer *buffer = g_new (PangoOTBuffer, 1);
|
||||||
|
FT_Face face = pango_fc_font_lock_face (font);
|
||||||
|
|
||||||
|
if (otl_buffer_new (face->memory, &buffer->buffer) != FT_Err_Ok)
|
||||||
|
g_error ("Allocation of OTLBuffer failed");
|
||||||
|
|
||||||
|
buffer->font = g_object_ref (font);
|
||||||
|
buffer->applied_gpos = FALSE;
|
||||||
|
buffer->rtl = FALSE;
|
||||||
|
|
||||||
|
pango_fc_font_unlock_face (font);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pango_ot_buffer_destroy (PangoOTBuffer *buffer)
|
||||||
|
{
|
||||||
|
otl_buffer_free (buffer->buffer);
|
||||||
|
g_object_unref (buffer->font);
|
||||||
|
g_free (buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pango_ot_buffer_clear (PangoOTBuffer *buffer)
|
||||||
|
{
|
||||||
|
otl_buffer_clear (buffer->buffer);
|
||||||
|
buffer->applied_gpos = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pango_ot_buffer_add_glyph (PangoOTBuffer *buffer,
|
||||||
|
guint glyph_index,
|
||||||
|
guint properties,
|
||||||
|
guint cluster)
|
||||||
|
{
|
||||||
|
otl_buffer_add_glyph (buffer->buffer,
|
||||||
|
glyph_index, properties, cluster);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pango_ot_buffer_set_rtl (PangoOTBuffer *buffer,
|
||||||
|
gboolean rtl)
|
||||||
|
{
|
||||||
|
rtl = rtl != FALSE;
|
||||||
|
buffer->rtl = rtl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pango_ot_buffer_get_glyphs (PangoOTBuffer *buffer,
|
||||||
|
PangoOTGlyph **glyphs,
|
||||||
|
int *n_glyphs)
|
||||||
|
{
|
||||||
|
if (glyphs)
|
||||||
|
*glyphs = (PangoOTGlyph *)buffer->buffer->in_string;
|
||||||
|
|
||||||
|
if (n_glyphs)
|
||||||
|
*n_glyphs = buffer->buffer->in_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
swap_range (PangoGlyphString *glyphs, int start, int end)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for (i = start, j = end - 1; i < j; i++, j--)
|
||||||
|
{
|
||||||
|
PangoGlyphInfo glyph_info;
|
||||||
|
gint log_cluster;
|
||||||
|
|
||||||
|
glyph_info = glyphs->glyphs[i];
|
||||||
|
glyphs->glyphs[i] = glyphs->glyphs[j];
|
||||||
|
glyphs->glyphs[j] = glyph_info;
|
||||||
|
|
||||||
|
log_cluster = glyphs->log_clusters[i];
|
||||||
|
glyphs->log_clusters[i] = glyphs->log_clusters[j];
|
||||||
|
glyphs->log_clusters[j] = log_cluster;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
apply_gpos_ltr (PangoGlyphString *glyphs,
|
||||||
|
OTL_Position positions)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < glyphs->num_glyphs; i++)
|
||||||
|
{
|
||||||
|
FT_Pos x_pos = positions[i].x_pos;
|
||||||
|
FT_Pos y_pos = positions[i].y_pos;
|
||||||
|
int back = i;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
while (positions[back].back != 0)
|
||||||
|
{
|
||||||
|
back -= positions[back].back;
|
||||||
|
x_pos += positions[back].x_pos;
|
||||||
|
y_pos += positions[back].y_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = back; j < i; j++)
|
||||||
|
glyphs->glyphs[i].geometry.x_offset -= glyphs->glyphs[j].geometry.width;
|
||||||
|
|
||||||
|
glyphs->glyphs[i].geometry.x_offset += PANGO_UNITS_26_6(x_pos);
|
||||||
|
glyphs->glyphs[i].geometry.y_offset += PANGO_UNITS_26_6(y_pos);
|
||||||
|
|
||||||
|
if (positions[i].new_advance)
|
||||||
|
glyphs->glyphs[i].geometry.width = PANGO_UNITS_26_6(positions[i].x_advance);
|
||||||
|
else
|
||||||
|
glyphs->glyphs[i].geometry.width += PANGO_UNITS_26_6(positions[i].x_advance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
apply_gpos_rtl (PangoGlyphString *glyphs,
|
||||||
|
OTL_Position positions)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < glyphs->num_glyphs; i++)
|
||||||
|
{
|
||||||
|
int i_rev = glyphs->num_glyphs - i - 1;
|
||||||
|
int back_rev = i_rev;
|
||||||
|
int back;
|
||||||
|
FT_Pos x_pos = positions[i_rev].x_pos;
|
||||||
|
FT_Pos y_pos = positions[i_rev].y_pos;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
while (positions[back_rev].back != 0)
|
||||||
|
{
|
||||||
|
back_rev -= positions[back_rev].back;
|
||||||
|
x_pos += positions[back_rev].x_pos;
|
||||||
|
y_pos += positions[back_rev].y_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
back = glyphs->num_glyphs - back_rev - 1;
|
||||||
|
|
||||||
|
for (j = i; j < back; j++)
|
||||||
|
glyphs->glyphs[i].geometry.x_offset += glyphs->glyphs[j].geometry.width;
|
||||||
|
|
||||||
|
glyphs->glyphs[i].geometry.x_offset += PANGO_UNITS_26_6(x_pos);
|
||||||
|
glyphs->glyphs[i].geometry.y_offset -= PANGO_UNITS_26_6(y_pos);
|
||||||
|
|
||||||
|
if (positions[i_rev].new_advance)
|
||||||
|
glyphs->glyphs[i].geometry.width = PANGO_UNITS_26_6(positions[i_rev].x_advance);
|
||||||
|
else
|
||||||
|
glyphs->glyphs[i].geometry.width += PANGO_UNITS_26_6(positions[i_rev].x_advance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pango_ot_buffer_output (PangoOTBuffer *buffer,
|
||||||
|
PangoGlyphString *glyphs)
|
||||||
|
{
|
||||||
|
FT_Face face;
|
||||||
|
PangoOTInfo *info;
|
||||||
|
TTO_GDEF gdef = NULL;
|
||||||
|
int i;
|
||||||
|
int last_cluster;
|
||||||
|
|
||||||
|
face = pango_fc_font_lock_face (buffer->font);
|
||||||
|
g_assert (face);
|
||||||
|
|
||||||
|
/* Copy glyphs into output glyph string */
|
||||||
|
pango_glyph_string_set_size (glyphs, buffer->buffer->in_length);
|
||||||
|
|
||||||
|
last_cluster = -1;
|
||||||
|
for (i = 0; i < buffer->buffer->in_length; i++)
|
||||||
|
{
|
||||||
|
OTL_GlyphItem item = &buffer->buffer->in_string[i];
|
||||||
|
|
||||||
|
glyphs->glyphs[i].glyph = item->gindex;
|
||||||
|
|
||||||
|
glyphs->log_clusters[i] = item->cluster;
|
||||||
|
if (glyphs->log_clusters[i] != last_cluster)
|
||||||
|
glyphs->glyphs[i].attr.is_cluster_start = 1;
|
||||||
|
else
|
||||||
|
glyphs->glyphs[i].attr.is_cluster_start = 0;
|
||||||
|
|
||||||
|
last_cluster = glyphs->log_clusters[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
info = pango_ot_info_get (face);
|
||||||
|
gdef = pango_ot_info_get_gdef (info);
|
||||||
|
|
||||||
|
/* Apply default positioning */
|
||||||
|
for (i = 0; i < glyphs->num_glyphs; i++)
|
||||||
|
{
|
||||||
|
if (glyphs->glyphs[i].glyph)
|
||||||
|
{
|
||||||
|
PangoRectangle logical_rect;
|
||||||
|
|
||||||
|
FT_UShort property;
|
||||||
|
|
||||||
|
if (gdef &&
|
||||||
|
TT_GDEF_Get_Glyph_Property (gdef, glyphs->glyphs[i].glyph, &property) == FT_Err_Ok &&
|
||||||
|
(property == TTO_MARK || (property & IGNORE_SPECIAL_MARKS) != 0))
|
||||||
|
{
|
||||||
|
glyphs->glyphs[i].geometry.width = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pango_font_get_glyph_extents ((PangoFont *)buffer->font, glyphs->glyphs[i].glyph, NULL, &logical_rect);
|
||||||
|
glyphs->glyphs[i].geometry.width = logical_rect.width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
glyphs->glyphs[i].geometry.width = 0;
|
||||||
|
|
||||||
|
glyphs->glyphs[i].geometry.x_offset = 0;
|
||||||
|
glyphs->glyphs[i].geometry.y_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer->rtl)
|
||||||
|
{
|
||||||
|
/* Swap all glyphs */
|
||||||
|
swap_range (glyphs, 0, glyphs->num_glyphs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer->applied_gpos)
|
||||||
|
{
|
||||||
|
if (buffer->rtl)
|
||||||
|
apply_gpos_rtl (glyphs, buffer->buffer->positions);
|
||||||
|
else
|
||||||
|
apply_gpos_ltr (glyphs, buffer->buffer->positions);
|
||||||
|
}
|
||||||
|
|
||||||
|
pango_fc_font_unlock_face (buffer->font);
|
||||||
|
}
|
|
@ -162,17 +162,31 @@ compare_glyph_info (gconstpointer a,
|
||||||
/* Make a guess at the appropriate class for a glyph given
|
/* Make a guess at the appropriate class for a glyph given
|
||||||
* a character code that maps to the glyph
|
* a character code that maps to the glyph
|
||||||
*/
|
*/
|
||||||
static FT_UShort
|
static gboolean
|
||||||
get_glyph_class (gunichar charcode)
|
get_glyph_class (gunichar charcode,
|
||||||
|
FT_UShort *class)
|
||||||
{
|
{
|
||||||
|
/* For characters mapped into the Arabic Presentation forms, using properties
|
||||||
|
* derived as we apply GSUB substitutions will be more reliable
|
||||||
|
*/
|
||||||
|
if ((charcode >= 0xFB50 && charcode <= 0xFDFF) || /* Arabic Presentation Forms-A */
|
||||||
|
(charcode >= 0xFE70 && charcode <= 0XFEFF)) /* Arabic Presentation Forms-B */
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
switch (g_unichar_type (charcode))
|
switch (g_unichar_type (charcode))
|
||||||
{
|
{
|
||||||
case G_UNICODE_COMBINING_MARK:
|
case G_UNICODE_COMBINING_MARK:
|
||||||
case G_UNICODE_ENCLOSING_MARK:
|
case G_UNICODE_ENCLOSING_MARK:
|
||||||
case G_UNICODE_NON_SPACING_MARK:
|
case G_UNICODE_NON_SPACING_MARK:
|
||||||
return 3; /* Mark glyph (non-spacing combining glyph) */
|
*class = 3; /* Mark glyph (non-spacing combining glyph) */
|
||||||
|
return TRUE;
|
||||||
|
case G_UNICODE_UNASSIGNED:
|
||||||
|
case G_UNICODE_PRIVATE_USE:
|
||||||
|
return FALSE; /* Unknown, don't assign a class; classes get
|
||||||
|
* propagated during GSUB application */
|
||||||
default:
|
default:
|
||||||
return 1; /* Base glyph (single character, spacing glyph) */
|
*class = 1; /* Base glyph (single character, spacing glyph) */
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,8 +239,7 @@ synthesize_class_def (PangoOTInfo *info)
|
||||||
if (glyph <= 65535)
|
if (glyph <= 65535)
|
||||||
{
|
{
|
||||||
glyph_info.glyph = glyph;
|
glyph_info.glyph = glyph;
|
||||||
glyph_info.class = get_glyph_class (charcode);
|
if (get_glyph_class (charcode, &glyph_info.class))
|
||||||
|
|
||||||
g_array_append_val (glyph_infos, glyph_info);
|
g_array_append_val (glyph_infos, glyph_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,14 @@ struct _PangoOTRulesetClass
|
||||||
GObjectClass parent_class;
|
GObjectClass parent_class;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct _PangoOTBuffer
|
||||||
|
{
|
||||||
|
OTL_Buffer buffer;
|
||||||
|
PangoFcFont *font;
|
||||||
|
gboolean rtl;
|
||||||
|
gboolean applied_gpos;
|
||||||
|
};
|
||||||
|
|
||||||
GType pango_ot_info_get_type (void);
|
GType pango_ot_info_get_type (void);
|
||||||
|
|
||||||
TTO_GDEF pango_ot_info_get_gdef (PangoOTInfo *info);
|
TTO_GDEF pango_ot_info_get_gdef (PangoOTInfo *info);
|
||||||
|
|
|
@ -24,9 +24,6 @@
|
||||||
|
|
||||||
#include FT_INTERNAL_MEMORY_H /* For FT_Free() */
|
#include FT_INTERNAL_MEMORY_H /* For FT_Free() */
|
||||||
|
|
||||||
#define PANGO_SCALE_26_6 (PANGO_SCALE / (1<<6))
|
|
||||||
#define PANGO_UNITS_26_6(d) (PANGO_SCALE_26_6 * (d))
|
|
||||||
|
|
||||||
typedef struct _PangoOTRule PangoOTRule;
|
typedef struct _PangoOTRule PangoOTRule;
|
||||||
|
|
||||||
struct _PangoOTRule
|
struct _PangoOTRule
|
||||||
|
@ -139,34 +136,15 @@ pango_ot_ruleset_add_feature (PangoOTRuleset *ruleset,
|
||||||
g_array_append_val (ruleset->rules, tmp_rule);
|
g_array_append_val (ruleset->rules, tmp_rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* pango_ot_ruleset_shape:
|
|
||||||
* @ruleset: a #PangoOTRuleset.
|
|
||||||
* @glyphs: a pointer to a #PangoGlyphString.
|
|
||||||
* @properties: an array containing one #gulong bitfield for each glyph,
|
|
||||||
* which gives the glyph's properties: If a certain bit is set for a glyph,
|
|
||||||
* the feature which has the same bit set in its property value is applied.
|
|
||||||
*
|
|
||||||
* Shapes a string of glyphs with the given properties according to @ruleset.
|
|
||||||
**/
|
|
||||||
void
|
void
|
||||||
pango_ot_ruleset_shape (PangoOTRuleset *ruleset,
|
pango_ot_ruleset_substitute (PangoOTRuleset *ruleset,
|
||||||
PangoGlyphString *glyphs,
|
PangoOTBuffer *buffer)
|
||||||
gulong *properties)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int last_cluster;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
TTO_GSUB gsub = NULL;
|
TTO_GSUB gsub = NULL;
|
||||||
TTO_GPOS gpos = NULL;
|
|
||||||
|
|
||||||
TTO_GSUB_String *in_string = NULL;
|
|
||||||
TTO_GSUB_String *out_string = NULL;
|
|
||||||
TTO_GSUB_String *result_string = NULL;
|
|
||||||
|
|
||||||
gboolean need_gsub = FALSE;
|
gboolean need_gsub = FALSE;
|
||||||
gboolean need_gpos = FALSE;
|
|
||||||
|
|
||||||
g_return_if_fail (PANGO_OT_IS_RULESET (ruleset));
|
g_return_if_fail (PANGO_OT_IS_RULESET (ruleset));
|
||||||
|
|
||||||
|
@ -176,26 +154,17 @@ pango_ot_ruleset_shape (PangoOTRuleset *ruleset,
|
||||||
|
|
||||||
if (rule->table_type == PANGO_OT_TABLE_GSUB)
|
if (rule->table_type == PANGO_OT_TABLE_GSUB)
|
||||||
need_gsub = TRUE;
|
need_gsub = TRUE;
|
||||||
else
|
|
||||||
need_gpos = TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (need_gsub)
|
if (need_gsub)
|
||||||
{
|
{
|
||||||
|
|
||||||
gsub = pango_ot_info_get_gsub (ruleset->info);
|
gsub = pango_ot_info_get_gsub (ruleset->info);
|
||||||
|
|
||||||
if (gsub)
|
if (gsub)
|
||||||
TT_GSUB_Clear_Features (gsub);
|
TT_GSUB_Clear_Features (gsub);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (need_gpos)
|
|
||||||
{
|
|
||||||
gpos = pango_ot_info_get_gpos (ruleset->info);
|
|
||||||
|
|
||||||
if (gpos)
|
|
||||||
TT_GPOS_Clear_Features (gpos);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < ruleset->rules->len; i++)
|
for (i = 0; i < ruleset->rules->len; i++)
|
||||||
{
|
{
|
||||||
PangoOTRule *rule = &g_array_index (ruleset->rules, PangoOTRule, i);
|
PangoOTRule *rule = &g_array_index (ruleset->rules, PangoOTRule, i);
|
||||||
|
@ -205,98 +174,59 @@ pango_ot_ruleset_shape (PangoOTRuleset *ruleset,
|
||||||
if (gsub)
|
if (gsub)
|
||||||
TT_GSUB_Add_Feature (gsub, rule->feature_index, rule->property_bit);
|
TT_GSUB_Add_Feature (gsub, rule->feature_index, rule->property_bit);
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
|
if (!gsub)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TT_GSUB_Apply_String (gsub, buffer->buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pango_ot_ruleset_position (PangoOTRuleset *ruleset,
|
||||||
|
PangoOTBuffer *buffer)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
TTO_GPOS gpos = NULL;
|
||||||
|
|
||||||
|
gboolean need_gpos = FALSE;
|
||||||
|
|
||||||
|
g_return_if_fail (PANGO_OT_IS_RULESET (ruleset));
|
||||||
|
|
||||||
|
for (i = 0; i < ruleset->rules->len; i++)
|
||||||
{
|
{
|
||||||
|
PangoOTRule *rule = &g_array_index (ruleset->rules, PangoOTRule, i);
|
||||||
|
|
||||||
|
if (rule->table_type == PANGO_OT_TABLE_GPOS)
|
||||||
|
need_gpos = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (need_gpos)
|
||||||
|
gpos = pango_ot_info_get_gpos (ruleset->info);
|
||||||
|
|
||||||
if (gpos)
|
if (gpos)
|
||||||
|
{
|
||||||
|
TT_GPOS_Clear_Features (gpos);
|
||||||
|
|
||||||
|
for (i = 0; i < ruleset->rules->len; i++)
|
||||||
|
{
|
||||||
|
PangoOTRule *rule = &g_array_index (ruleset->rules, PangoOTRule, i);
|
||||||
|
|
||||||
|
if (rule->table_type == PANGO_OT_TABLE_GPOS)
|
||||||
TT_GPOS_Add_Feature (gpos, rule->feature_index, rule->property_bit);
|
TT_GPOS_Add_Feature (gpos, rule->feature_index, rule->property_bit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gsub && !gpos)
|
/* Apply GPOS rules */
|
||||||
return;
|
|
||||||
|
|
||||||
result = TT_GSUB_String_New (ruleset->info->face->memory, &in_string);
|
|
||||||
g_assert (result == FT_Err_Ok);
|
|
||||||
|
|
||||||
result = TT_GSUB_String_Set_Length (in_string, glyphs->num_glyphs);
|
|
||||||
g_assert (result == FT_Err_Ok);
|
|
||||||
|
|
||||||
for (i = 0; i < glyphs->num_glyphs; i++)
|
|
||||||
{
|
|
||||||
in_string->string[i] = glyphs->glyphs[i].glyph;
|
|
||||||
in_string->properties[i] = properties[i];
|
|
||||||
in_string->logClusters[i] = glyphs->log_clusters[i];
|
|
||||||
}
|
|
||||||
in_string->max_ligID = i;
|
|
||||||
|
|
||||||
if (gsub)
|
|
||||||
{
|
|
||||||
result = TT_GSUB_String_New (ruleset->info->face->memory,
|
|
||||||
&out_string);
|
|
||||||
g_assert (result == FT_Err_Ok);
|
|
||||||
result_string = out_string;
|
|
||||||
|
|
||||||
TT_GSUB_Apply_String (gsub, in_string, out_string);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
result_string = in_string;
|
|
||||||
|
|
||||||
if (gpos)
|
if (gpos)
|
||||||
{
|
{
|
||||||
TTO_GPOS_Data *outgpos = NULL;
|
if (TT_GPOS_Apply_String (ruleset->info->face, gpos, 0, buffer->buffer,
|
||||||
|
|
||||||
if (!TT_GPOS_Apply_String (ruleset->info->face, gpos, 0, result_string, &outgpos,
|
|
||||||
FALSE /* enable device-dependant values */,
|
FALSE /* enable device-dependant values */,
|
||||||
FALSE /* Even though this might be r2l text, RTL is handled elsewhere */))
|
buffer->rtl) == FT_Err_Ok)
|
||||||
{
|
{
|
||||||
for (i = 0; i < result_string->length; i++)
|
buffer->applied_gpos = TRUE;
|
||||||
{
|
|
||||||
FT_Pos x_pos = outgpos[i].x_pos;
|
|
||||||
FT_Pos y_pos = outgpos[i].y_pos;
|
|
||||||
int back = i;
|
|
||||||
int j;
|
|
||||||
|
|
||||||
while (outgpos[back].back != 0)
|
|
||||||
{
|
|
||||||
back -= outgpos[back].back;
|
|
||||||
x_pos += outgpos[back].x_pos;
|
|
||||||
y_pos += outgpos[back].y_pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (j = back; j < i; j++)
|
|
||||||
glyphs->glyphs[i].geometry.x_offset -= glyphs->glyphs[j].geometry.width;
|
|
||||||
|
|
||||||
glyphs->glyphs[i].geometry.x_offset += PANGO_UNITS_26_6(x_pos);
|
|
||||||
glyphs->glyphs[i].geometry.y_offset -= PANGO_UNITS_26_6(y_pos);
|
|
||||||
|
|
||||||
if (outgpos[i].new_advance)
|
|
||||||
glyphs->glyphs[i].geometry.width = PANGO_UNITS_26_6(outgpos[i].x_advance);
|
|
||||||
else
|
|
||||||
glyphs->glyphs[i].geometry.width += PANGO_UNITS_26_6(outgpos[i].x_advance);
|
|
||||||
}
|
|
||||||
|
|
||||||
FT_Free(gpos->memory, (void *)outgpos);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pango_glyph_string_set_size (glyphs, result_string->length);
|
|
||||||
|
|
||||||
last_cluster = -1;
|
|
||||||
for (i = 0; i < result_string->length; i++)
|
|
||||||
{
|
|
||||||
glyphs->glyphs[i].glyph = result_string->string[i];
|
|
||||||
|
|
||||||
glyphs->log_clusters[i] = result_string->logClusters[i];
|
|
||||||
if (glyphs->log_clusters[i] != last_cluster)
|
|
||||||
glyphs->glyphs[i].attr.is_cluster_start = 1;
|
|
||||||
else
|
|
||||||
glyphs->glyphs[i].attr.is_cluster_start = 0;
|
|
||||||
|
|
||||||
last_cluster = glyphs->log_clusters[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_string)
|
|
||||||
TT_GSUB_String_Done (in_string);
|
|
||||||
if (out_string)
|
|
||||||
TT_GSUB_String_Done (out_string);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue