blob: 4804bc1d1bb0c02962a36bb55c205f16c1b37614 [file] [log] [blame]
// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#include "../../../include/fxge/fx_freetype.h"
#include "third_party/freetype/src/psnames/pstables.h"
static int xyq_search_node(char* glyph_name, int name_offset, int table_offset, wchar_t unicode)
{
int i, count;
// copy letters
while (1) {
glyph_name[name_offset] = ft_adobe_glyph_list[table_offset] & 0x7f;
name_offset++;
table_offset++;
if (!(ft_adobe_glyph_list[table_offset - 1] & 0x80)) break;
}
glyph_name[name_offset] = 0;
// get child count
count = ft_adobe_glyph_list[table_offset] & 0x7f;
// check if we have value for this node
if (ft_adobe_glyph_list[table_offset] & 0x80) {
unsigned short thiscode = ft_adobe_glyph_list[table_offset + 1] * 256 + ft_adobe_glyph_list[table_offset + 2];
if (thiscode == (unsigned short)unicode) // found it!
return 1;
table_offset += 3;
}
else
table_offset++;
// now search in sub-nodes
if (count == 0) return 0;
for (i = 0; i < count; i++) {
int child_offset = ft_adobe_glyph_list[table_offset + i * 2] * 256 + ft_adobe_glyph_list[table_offset + i * 2 + 1];
if (xyq_search_node(glyph_name, name_offset, child_offset, unicode))
// found in child
return 1;
}
return 0;
}
#define VARIANT_BIT 0x80000000UL
int FXFT_unicode_from_adobe_name(const char* glyph_name)
{
/* If the name begins with `uni', then the glyph name may be a */
/* hard-coded unicode character code. */
if (glyph_name[0] == 'u' &&
glyph_name[1] == 'n' &&
glyph_name[2] == 'i')
{
/* determine whether the next four characters following are */
/* hexadecimal. */
/* XXX: Add code to deal with ligatures, i.e. glyph names like */
/* `uniXXXXYYYYZZZZ'... */
FT_Int count;
FT_UInt32 value = 0;
const char* p = glyph_name + 3;
for (count = 4; count > 0; count--, p++)
{
char c = *p;
unsigned int d;
d = (unsigned char)c - '0';
if (d >= 10)
{
d = (unsigned char)c - 'A';
if (d >= 6)
d = 16;
else
d += 10;
}
/* Exit if a non-uppercase hexadecimal character was found */
/* -- this also catches character codes below `0' since such */
/* negative numbers cast to `unsigned int' are far too big. */
if (d >= 16)
break;
value = (value << 4) + d;
}
/* there must be exactly four hex digits */
if (count == 0)
{
if (*p == '\0')
return value;
if (*p == '.')
return (FT_UInt32)(value | VARIANT_BIT);
}
}
/* If the name begins with `u', followed by four to six uppercase */
/* hexadecimal digits, it is a hard-coded unicode character code. */
if (glyph_name[0] == 'u')
{
FT_Int count;
FT_UInt32 value = 0;
const char* p = glyph_name + 1;
for (count = 6; count > 0; count--, p++)
{
char c = *p;
unsigned int d;
d = (unsigned char)c - '0';
if (d >= 10)
{
d = (unsigned char)c - 'A';
if (d >= 6)
d = 16;
else
d += 10;
}
if (d >= 16)
break;
value = (value << 4) + d;
}
if (count <= 2)
{
if (*p == '\0')
return value;
if (*p == '.')
return (FT_UInt32)(value | VARIANT_BIT);
}
}
/* Look for a non-initial dot in the glyph name in order to */
/* find variants like `A.swash', `e.final', etc. */
{
const char* p = glyph_name;
const char* dot = NULL;
for (; *p; p++)
{
if (*p == '.' && p > glyph_name)
{
dot = p;
break;
}
}
/* now look up the glyph in the Adobe Glyph List */
if (!dot)
return (FT_UInt32)ft_get_adobe_glyph_index(glyph_name, p);
else
return (FT_UInt32)(ft_get_adobe_glyph_index(glyph_name, dot) |
VARIANT_BIT);
}
}
void FXFT_adobe_name_from_unicode(char* glyph_name, wchar_t unicode)
{
int i, count;
// start from top level node
count = ft_adobe_glyph_list[1];
for (i = 0; i < count; i++) {
int child_offset = ft_adobe_glyph_list[i * 2 + 2] * 256 + ft_adobe_glyph_list[i * 2 + 3];
if (xyq_search_node(glyph_name, 0, child_offset, unicode))
return;
}
// failed, clear the buffer
glyph_name[0] = 0;
}