188 lines
6.5 KiB
C
188 lines
6.5 KiB
C
/*
|
|
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
|
|
*
|
|
* This is part of HarfBuzz, an OpenType Layout engine library.
|
|
*
|
|
* Permission is hereby granted, without written agreement and without
|
|
* license or royalty fees, to use, copy, modify, and distribute this
|
|
* software and its documentation for any purpose, provided that the
|
|
* above copyright notice and the following two paragraphs appear in
|
|
* all copies of this software.
|
|
*
|
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
|
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
|
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
|
* DAMAGE.
|
|
*
|
|
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
|
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
|
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
|
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
*/
|
|
|
|
#include "harfbuzz-shaper.h"
|
|
#include "harfbuzz-shaper-private.h"
|
|
#include <assert.h>
|
|
|
|
/*
|
|
// Uniscribe also defines dlig for Hebrew, but we leave this out for now, as it's mostly
|
|
// ligatures one does not want in modern Hebrew (as lam-alef ligatures).
|
|
*/
|
|
#ifndef NO_OPENTYPE
|
|
static const HB_OpenTypeFeature hebrew_features[] = {
|
|
{ HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty },
|
|
{0, 0}
|
|
};
|
|
#endif
|
|
|
|
/* Hebrew shaping. In the non opentype case we try to use the
|
|
presentation forms specified for Hebrew. Especially for the
|
|
ligatures with Dagesh this gives much better results than we could
|
|
achieve manually.
|
|
*/
|
|
HB_Bool HB_HebrewShape(HB_ShaperItem *shaper_item)
|
|
{
|
|
enum {
|
|
Dagesh = 0x5bc,
|
|
ShinDot = 0x5c1,
|
|
SinDot = 0x5c2,
|
|
Patah = 0x5b7,
|
|
Qamats = 0x5b8,
|
|
Holam = 0x5b9,
|
|
Rafe = 0x5bf
|
|
};
|
|
|
|
assert(shaper_item->item.script == HB_Script_Hebrew);
|
|
|
|
#ifndef NO_OPENTYPE
|
|
if (HB_SelectScript(shaper_item, hebrew_features)) {
|
|
|
|
const int availableGlyphs = shaper_item->num_glyphs;
|
|
if (!HB_ConvertStringToGlyphIndices(shaper_item))
|
|
return FALSE;
|
|
|
|
HB_HeuristicSetGlyphAttributes(shaper_item);
|
|
HB_OpenTypeShape(shaper_item, /*properties*/0);
|
|
return HB_OpenTypePosition(shaper_item, availableGlyphs, /*doLogClusters*/TRUE);
|
|
}
|
|
#endif
|
|
|
|
{
|
|
const HB_UChar16 *uc = shaper_item->string + shaper_item->item.pos;
|
|
unsigned short *logClusters = shaper_item->log_clusters;
|
|
HB_GlyphAttributes *attributes = shaper_item->attributes;
|
|
|
|
HB_Bool haveGlyphs;
|
|
int slen = 1;
|
|
int cluster_start = 0;
|
|
hb_uint32 i;
|
|
|
|
HB_STACKARRAY(HB_UChar16, shapedChars, 2 * shaper_item->item.length);
|
|
*shapedChars = *uc;
|
|
logClusters[0] = 0;
|
|
|
|
for (i = 1; i < shaper_item->item.length; ++i) {
|
|
hb_uint16 base = shapedChars[cluster_start];
|
|
hb_uint16 shaped = 0;
|
|
HB_Bool invalid = FALSE;
|
|
if (uc[i] == Dagesh) {
|
|
if (base >= 0x5d0
|
|
&& base <= 0x5ea
|
|
&& base != 0x5d7
|
|
&& base != 0x5dd
|
|
&& base != 0x5df
|
|
&& base != 0x5e2
|
|
&& base != 0x5e5) {
|
|
shaped = base - 0x5d0 + 0xfb30;
|
|
} else if (base == 0xfb2a || base == 0xfb2b /* Shin with Shin or Sin dot */) {
|
|
shaped = base + 2;
|
|
} else {
|
|
invalid = TRUE;
|
|
}
|
|
} else if (uc[i] == ShinDot) {
|
|
if (base == 0x05e9)
|
|
shaped = 0xfb2a;
|
|
else if (base == 0xfb49)
|
|
shaped = 0xfb2c;
|
|
else
|
|
invalid = TRUE;
|
|
} else if (uc[i] == SinDot) {
|
|
if (base == 0x05e9)
|
|
shaped = 0xfb2b;
|
|
else if (base == 0xfb49)
|
|
shaped = 0xfb2d;
|
|
else
|
|
invalid = TRUE;
|
|
} else if (uc[i] == Patah) {
|
|
if (base == 0x5d0)
|
|
shaped = 0xfb2e;
|
|
} else if (uc[i] == Qamats) {
|
|
if (base == 0x5d0)
|
|
shaped = 0xfb2f;
|
|
} else if (uc[i] == Holam) {
|
|
if (base == 0x5d5)
|
|
shaped = 0xfb4b;
|
|
} else if (uc[i] == Rafe) {
|
|
if (base == 0x5d1)
|
|
shaped = 0xfb4c;
|
|
else if (base == 0x5db)
|
|
shaped = 0xfb4d;
|
|
else if (base == 0x5e4)
|
|
shaped = 0xfb4e;
|
|
}
|
|
|
|
if (invalid) {
|
|
shapedChars[slen] = 0x25cc;
|
|
attributes[slen].clusterStart = TRUE;
|
|
attributes[slen].mark = FALSE;
|
|
attributes[slen].combiningClass = 0;
|
|
cluster_start = slen;
|
|
++slen;
|
|
}
|
|
if (shaped) {
|
|
if (shaper_item->font->klass->canRender(shaper_item->font, (HB_UChar16 *)&shaped, 1)) {
|
|
shapedChars[cluster_start] = shaped;
|
|
} else
|
|
shaped = 0;
|
|
}
|
|
if (!shaped) {
|
|
HB_CharCategory category;
|
|
int cmb;
|
|
shapedChars[slen] = uc[i];
|
|
HB_GetUnicodeCharProperties(uc[i], &category, &cmb);
|
|
if (category != HB_Mark_NonSpacing) {
|
|
attributes[slen].clusterStart = TRUE;
|
|
attributes[slen].mark = FALSE;
|
|
attributes[slen].combiningClass = 0;
|
|
attributes[slen].dontPrint = HB_IsControlChar(uc[i]);
|
|
cluster_start = slen;
|
|
} else {
|
|
attributes[slen].clusterStart = FALSE;
|
|
attributes[slen].mark = TRUE;
|
|
attributes[slen].combiningClass = cmb;
|
|
}
|
|
++slen;
|
|
}
|
|
logClusters[i] = cluster_start;
|
|
}
|
|
|
|
haveGlyphs = shaper_item->font->klass
|
|
->convertStringToGlyphIndices(shaper_item->font,
|
|
shapedChars, slen,
|
|
shaper_item->glyphs, &shaper_item->num_glyphs,
|
|
shaper_item->item.bidiLevel % 2);
|
|
|
|
HB_FREE_STACKARRAY(shapedChars);
|
|
|
|
if (!haveGlyphs)
|
|
return FALSE;
|
|
|
|
HB_HeuristicPosition(shaper_item);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|