summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/harfbuzz/src/harfbuzz-hangul.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/harfbuzz/src/harfbuzz-hangul.c')
-rw-r--r--src/3rdparty/harfbuzz/src/harfbuzz-hangul.c268
1 files changed, 268 insertions, 0 deletions
diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-hangul.c b/src/3rdparty/harfbuzz/src/harfbuzz-hangul.c
new file mode 100644
index 0000000000..6f89ed6b0b
--- /dev/null
+++ b/src/3rdparty/harfbuzz/src/harfbuzz-hangul.c
@@ -0,0 +1,268 @@
+/*
+ * 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>
+
+/*
+// Hangul is a syllable based script. Unicode reserves a large range
+// for precomposed hangul, where syllables are already precomposed to
+// their final glyph shape. In addition, a so called jamo range is
+// defined, that can be used to express old Hangul. Modern hangul
+// syllables can also be expressed as jamo, and should be composed
+// into syllables. The operation is rather simple and mathematical.
+
+// Every hangul jamo is classified as being either a Leading consonant
+// (L), and intermediat Vowel (V) or a trailing consonant (T). Modern
+// hangul syllables (the ones in the precomposed area can be of type
+// LV or LVT.
+//
+// Syllable breaks do _not_ occur between:
+//
+// L L, V or precomposed
+// V, LV V, T
+// LVT, T T
+//
+// A standard syllable is of the form L+V+T*. The above rules allow
+// nonstandard syllables L*V*T*. To transform them into standard
+// syllables fill characters L_f and V_f can be inserted.
+*/
+
+enum {
+ Hangul_SBase = 0xac00,
+ Hangul_LBase = 0x1100,
+ Hangul_VBase = 0x1161,
+ Hangul_TBase = 0x11a7,
+ Hangul_SCount = 11172,
+ Hangul_LCount = 19,
+ Hangul_VCount = 21,
+ Hangul_TCount = 28,
+ Hangul_NCount = 21*28
+};
+
+#define hangul_isPrecomposed(uc) \
+ (uc >= Hangul_SBase && uc < Hangul_SBase + Hangul_SCount)
+
+#define hangul_isLV(uc) \
+ ((uc - Hangul_SBase) % Hangul_TCount == 0)
+
+typedef enum {
+ L,
+ V,
+ T,
+ LV,
+ LVT,
+ X
+} HangulType;
+
+static HangulType hangul_type(unsigned short uc) {
+ if (uc > Hangul_SBase && uc < Hangul_SBase + Hangul_SCount)
+ return hangul_isLV(uc) ? LV : LVT;
+ if (uc < Hangul_LBase || uc > 0x11ff)
+ return X;
+ if (uc < Hangul_VBase)
+ return L;
+ if (uc < Hangul_TBase)
+ return V;
+ return T;
+}
+
+static int hangul_nextSyllableBoundary(const HB_UChar16 *s, int start, int end)
+{
+ const HB_UChar16 *uc = s + start;
+
+ HangulType state = hangul_type(*uc);
+ int pos = 1;
+
+ while (pos < end - start) {
+ HangulType newState = hangul_type(uc[pos]);
+ switch(newState) {
+ case X:
+ goto finish;
+ case L:
+ case V:
+ case T:
+ if (state > newState)
+ goto finish;
+ state = newState;
+ break;
+ case LV:
+ if (state > L)
+ goto finish;
+ state = V;
+ break;
+ case LVT:
+ if (state > L)
+ goto finish;
+ state = T;
+ }
+ ++pos;
+ }
+
+ finish:
+ return start+pos;
+}
+
+#ifndef NO_OPENTYPE
+static const HB_OpenTypeFeature hangul_features [] = {
+ { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty },
+ { HB_MAKE_TAG('l', 'j', 'm', 'o'), CcmpProperty },
+ { HB_MAKE_TAG('v', 'j', 'm', 'o'), CcmpProperty },
+ { HB_MAKE_TAG('t', 'j', 'm', 'o'), CcmpProperty },
+ { 0, 0 }
+};
+#endif
+
+static HB_Bool hangul_shape_syllable(HB_ShaperItem *item, HB_Bool openType)
+{
+ const HB_UChar16 *ch = item->string + item->item.pos;
+ int len = item->item.length;
+#ifndef NO_OPENTYPE
+ const int availableGlyphs = item->num_glyphs;
+#endif
+
+ int i;
+ HB_UChar16 composed = 0;
+ /* see if we can compose the syllable into a modern hangul */
+ if (item->item.length == 2) {
+ int LIndex = ch[0] - Hangul_LBase;
+ int VIndex = ch[1] - Hangul_VBase;
+ if (LIndex >= 0 && LIndex < Hangul_LCount &&
+ VIndex >= 0 && VIndex < Hangul_VCount)
+ composed = (LIndex * Hangul_VCount + VIndex) * Hangul_TCount + Hangul_SBase;
+ } else if (item->item.length == 3) {
+ int LIndex = ch[0] - Hangul_LBase;
+ int VIndex = ch[1] - Hangul_VBase;
+ int TIndex = ch[2] - Hangul_TBase;
+ if (LIndex >= 0 && LIndex < Hangul_LCount &&
+ VIndex >= 0 && VIndex < Hangul_VCount &&
+ TIndex >= 0 && TIndex < Hangul_TCount)
+ composed = (LIndex * Hangul_VCount + VIndex) * Hangul_TCount + TIndex + Hangul_SBase;
+ }
+
+
+
+ /* if we have a modern hangul use the composed form */
+ if (composed) {
+ ch = &composed;
+ len = 1;
+ }
+
+ if (!item->font->klass->convertStringToGlyphIndices(item->font,
+ ch, len,
+ item->glyphs, &item->num_glyphs,
+ item->item.bidiLevel % 2))
+ return FALSE;
+ for (i = 0; i < len; i++) {
+ item->attributes[i].mark = FALSE;
+ item->attributes[i].clusterStart = FALSE;
+ item->attributes[i].justification = 0;
+ item->attributes[i].zeroWidth = FALSE;
+ /*IDEBUG(" %d: %4x", i, ch[i].unicode()); */
+ }
+
+#ifndef NO_OPENTYPE
+ if (!composed && openType) {
+ HB_Bool positioned;
+
+ HB_STACKARRAY(unsigned short, logClusters, len);
+ for (i = 0; i < len; ++i)
+ logClusters[i] = i;
+ item->log_clusters = logClusters;
+
+ HB_OpenTypeShape(item, /*properties*/0);
+
+ positioned = HB_OpenTypePosition(item, availableGlyphs, /*doLogClusters*/FALSE);
+
+ HB_FREE_STACKARRAY(logClusters);
+
+ if (!positioned)
+ return FALSE;
+ } else {
+ HB_HeuristicPosition(item);
+ }
+#endif
+
+ item->attributes[0].clusterStart = TRUE;
+ return TRUE;
+}
+
+HB_Bool HB_HangulShape(HB_ShaperItem *item)
+{
+ const HB_UChar16 *uc = item->string + item->item.pos;
+ HB_Bool allPrecomposed = TRUE;
+ int i;
+
+ assert(item->item.script == HB_Script_Hangul);
+
+ for (i = 0; i < (int)item->item.length; ++i) {
+ if (!hangul_isPrecomposed(uc[i])) {
+ allPrecomposed = FALSE;
+ break;
+ }
+ }
+
+ if (!allPrecomposed) {
+ HB_Bool openType = FALSE;
+ unsigned short *logClusters = item->log_clusters;
+ HB_ShaperItem syllable;
+ int first_glyph = 0;
+ int sstart = item->item.pos;
+ int end = sstart + item->item.length;
+
+#ifndef NO_OPENTYPE
+ openType = HB_SelectScript(item, hangul_features);
+#endif
+ syllable = *item;
+
+ while (sstart < end) {
+ int send = hangul_nextSyllableBoundary(item->string, sstart, end);
+
+ syllable.item.pos = sstart;
+ syllable.item.length = send-sstart;
+ syllable.glyphs = item->glyphs + first_glyph;
+ syllable.attributes = item->attributes + first_glyph;
+ syllable.offsets = item->offsets + first_glyph;
+ syllable.advances = item->advances + first_glyph;
+ syllable.num_glyphs = item->num_glyphs - first_glyph;
+ if (!hangul_shape_syllable(&syllable, openType)) {
+ item->num_glyphs += syllable.num_glyphs;
+ return FALSE;
+ }
+ /* fix logcluster array */
+ for (i = sstart; i < send; ++i)
+ logClusters[i-item->item.pos] = first_glyph;
+ sstart = send;
+ first_glyph += syllable.num_glyphs;
+ }
+ item->num_glyphs = first_glyph;
+ return TRUE;
+ }
+
+ return HB_BasicShape(item);
+}
+
+