Emoji, Script, and Width iterators for Unicode string

This commit is contained in:
Vincent Wei
2019-03-18 17:32:27 +08:00
parent 8a856e5b99
commit aab8d6e2c6
8 changed files with 898 additions and 25 deletions
+11 -4
View File
@@ -12410,9 +12410,14 @@ typedef enum {
GLYPH_ORIENT_EAST = GLYPH_GRAVITY_EAST,
GLYPH_ORIENT_WEST = GLYPH_GRAVITY_WEST,
GLYPH_ORIENT_SOUTH = GLYPH_GRAVITY_SOUTH,
GLYPH_ORIENT_MIXED,
} GlyphOrient;
typedef enum {
GLYPH_ORIENT_POLICY_NATURAL,
GLYPH_ORIENT_POLICY_STRONG,
GLYPH_ORIENT_POLICY_LINE,
} GlyphOrientPolicy;
/**
* Split a Uchar32 paragraph string into text runs according to the
* scripts of characters.
@@ -12421,9 +12426,11 @@ typedef enum {
* breaking opportunities of the string.
*/
MG_EXPORT GLYPHRUNINFO* GUIAPI CreateGlyphRunInfo(Uchar32* ucs, int nr_ucs,
const char* lang_tag, const char* script_tag,
GlyphRunDir run_dir, GlyphOrient glyph_orient, ParagraphDir base_dir,
Uint8 ctr, Uint8 wbr, Uint8 lbp, LOGFONT* logfont, RGBCOLOR color);
LanguageCode lang_code, ScriptType script_type,
ParagraphDir base_dir, GlyphRunDir run_dir,
GlyphOrient glyph_orient, GlyphOrientPolicy orient_policy,
Uint8 ctr, Uint8 wbr, Uint8 lbp,
LOGFONT* logfont, RGBCOLOR color);
/**
* Set font of part characters. Please call this function before
+4 -2
View File
@@ -16,7 +16,8 @@ SRC_FILES = charset.c charset-arabic.c legacy-bidi.c charset-unicode.c \
unicode-bidi.c \
unicode-break.c \
unicode-joining-types.c unicode-joining.c unicode-shape.c \
unicode-shape-arabic.c harzbuff-minigui-funcs.c
unicode-shape-arabic.c harzbuff-minigui-funcs.c \
unicode-iterators.c
HDR_FILES = charset.h rawbitmap.h varbitmap.h freetype2.h qpf.h se_minigui.h \
upf.h bitmapfont.h unicode-bidi-tables.h \
@@ -34,7 +35,8 @@ HDR_FILES = charset.h rawbitmap.h varbitmap.h freetype2.h qpf.h se_minigui.h \
unicode-bidi-brackets-table.inc \
unicode-bidi-brackets-type-table.inc \
unicode-bidi-mirroring-table.inc \
script-language-table.inc
script-language-table.inc \
emoji_presentation_scanner.inc
EXTRA_DIST = convgbmap.c jisunimap.c $(SRC_FILES) $(HDR_FILES) \
makefile.ng makefile.msvc
+284
View File
@@ -0,0 +1,284 @@
#line 1 "emoji_presentation_scanner.rl"
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#line 9 "emoji_presentation_scanner.c"
static const char _emoji_presentation_actions[] = {
0, 1, 0, 1, 1, 1, 5, 1,
6, 1, 7, 1, 8, 1, 9, 1,
10, 1, 11, 2, 2, 3, 2, 2,
4
};
static const char _emoji_presentation_key_offsets[] = {
0, 5, 7, 14, 18, 20, 21, 24,
29, 30, 34, 36
};
static const unsigned char _emoji_presentation_trans_keys[] = {
3u, 7u, 13u, 0u, 2u, 14u, 15u, 2u,
3u, 6u, 7u, 13u, 0u, 1u, 9u, 10u,
11u, 12u, 10u, 12u, 10u, 4u, 10u, 12u,
4u, 9u, 10u, 11u, 12u, 6u, 9u, 10u,
11u, 12u, 8u, 10u, 9u, 10u, 11u, 12u,
14u, 0
};
static const char _emoji_presentation_single_lengths[] = {
3, 2, 5, 4, 2, 1, 3, 5,
1, 4, 2, 5
};
static const char _emoji_presentation_range_lengths[] = {
1, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0
};
static const char _emoji_presentation_index_offsets[] = {
0, 5, 8, 15, 20, 23, 25, 29,
35, 37, 42, 45
};
static const char _emoji_presentation_indicies[] = {
2, 1, 1, 1, 0, 4, 5, 3,
7, 8, 10, 11, 12, 6, 9, 5,
13, 14, 15, 0, 13, 15, 16, 13,
16, 15, 13, 15, 16, 15, 5, 13,
14, 15, 16, 5, 17, 5, 13, 14,
18, 17, 5, 13, 16, 5, 13, 14,
15, 4, 16, 0
};
static const char _emoji_presentation_trans_targs[] = {
2, 4, 6, 2, 1, 2, 3, 3,
7, 2, 8, 9, 11, 0, 2, 5,
2, 2, 10
};
static const char _emoji_presentation_trans_actions[] = {
17, 19, 19, 15, 0, 7, 22, 19,
19, 9, 0, 22, 19, 0, 5, 19,
11, 13, 19
};
static const char _emoji_presentation_to_state_actions[] = {
0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0
};
static const char _emoji_presentation_from_state_actions[] = {
0, 0, 3, 0, 0, 0, 0, 0,
0, 0, 0, 0
};
static const char _emoji_presentation_eof_trans[] = {
1, 4, 0, 1, 17, 17, 17, 17,
18, 18, 17, 17
};
static const int emoji_presentation_start = 2;
static const int emoji_presentation_en_text_and_emoji_run = 2;
#line 9 "emoji_presentation_scanner.rl"
#line 78 "emoji_presentation_scanner.rl"
static emoji_text_iter_t
scan_emoji_presentation (emoji_text_iter_t p,
const emoji_text_iter_t pe,
bool* is_emoji)
{
emoji_text_iter_t ts, te;
const emoji_text_iter_t eof = pe;
unsigned act;
int cs;
#line 107 "emoji_presentation_scanner.c"
{
cs = emoji_presentation_start;
ts = 0;
te = 0;
act = 0;
}
#line 115 "emoji_presentation_scanner.c"
{
int _klen;
unsigned int _trans;
const char *_acts;
unsigned int _nacts;
const unsigned char *_keys;
if ( p == pe )
goto _test_eof;
_resume:
_acts = _emoji_presentation_actions + _emoji_presentation_from_state_actions[cs];
_nacts = (unsigned int) *_acts++;
while ( _nacts-- > 0 ) {
switch ( *_acts++ ) {
case 1:
#line 1 "NONE"
{ts = p;}
break;
#line 134 "emoji_presentation_scanner.c"
}
}
_keys = _emoji_presentation_trans_keys + _emoji_presentation_key_offsets[cs];
_trans = _emoji_presentation_index_offsets[cs];
_klen = _emoji_presentation_single_lengths[cs];
if ( _klen > 0 ) {
const unsigned char *_lower = _keys;
const unsigned char *_mid;
const unsigned char *_upper = _keys + _klen - 1;
while (1) {
if ( _upper < _lower )
break;
_mid = _lower + ((_upper-_lower) >> 1);
if ( (*p) < *_mid )
_upper = _mid - 1;
else if ( (*p) > *_mid )
_lower = _mid + 1;
else {
_trans += (unsigned int)(_mid - _keys);
goto _match;
}
}
_keys += _klen;
_trans += _klen;
}
_klen = _emoji_presentation_range_lengths[cs];
if ( _klen > 0 ) {
const unsigned char *_lower = _keys;
const unsigned char *_mid;
const unsigned char *_upper = _keys + (_klen<<1) - 2;
while (1) {
if ( _upper < _lower )
break;
_mid = _lower + (((_upper-_lower) >> 1) & ~1);
if ( (*p) < _mid[0] )
_upper = _mid - 2;
else if ( (*p) > _mid[1] )
_lower = _mid + 2;
else {
_trans += (unsigned int)((_mid - _keys)>>1);
goto _match;
}
}
_trans += _klen;
}
_match:
_trans = _emoji_presentation_indicies[_trans];
_eof_trans:
cs = _emoji_presentation_trans_targs[_trans];
if ( _emoji_presentation_trans_actions[_trans] == 0 )
goto _again;
_acts = _emoji_presentation_actions + _emoji_presentation_trans_actions[_trans];
_nacts = (unsigned int) *_acts++;
while ( _nacts-- > 0 )
{
switch ( *_acts++ )
{
case 2:
#line 1 "NONE"
{te = p+1;}
break;
case 3:
#line 74 "emoji_presentation_scanner.rl"
{act = 2;}
break;
case 4:
#line 75 "emoji_presentation_scanner.rl"
{act = 3;}
break;
case 5:
#line 73 "emoji_presentation_scanner.rl"
{te = p+1;{ *is_emoji = false; return te; }}
break;
case 6:
#line 74 "emoji_presentation_scanner.rl"
{te = p+1;{ *is_emoji = true; return te; }}
break;
case 7:
#line 75 "emoji_presentation_scanner.rl"
{te = p+1;{ *is_emoji = false; return te; }}
break;
case 8:
#line 74 "emoji_presentation_scanner.rl"
{te = p;p--;{ *is_emoji = true; return te; }}
break;
case 9:
#line 75 "emoji_presentation_scanner.rl"
{te = p;p--;{ *is_emoji = false; return te; }}
break;
case 10:
#line 74 "emoji_presentation_scanner.rl"
{{p = ((te))-1;}{ *is_emoji = true; return te; }}
break;
case 11:
#line 1 "NONE"
{ switch( act ) {
case 2:
{{p = ((te))-1;} *is_emoji = true; return te; }
break;
case 3:
{{p = ((te))-1;} *is_emoji = false; return te; }
break;
}
}
break;
#line 248 "emoji_presentation_scanner.c"
}
}
_again:
_acts = _emoji_presentation_actions + _emoji_presentation_to_state_actions[cs];
_nacts = (unsigned int) *_acts++;
while ( _nacts-- > 0 ) {
switch ( *_acts++ ) {
case 0:
#line 1 "NONE"
{ts = 0;}
break;
#line 261 "emoji_presentation_scanner.c"
}
}
if ( ++p != pe )
goto _resume;
_test_eof: {}
if ( p == eof )
{
if ( _emoji_presentation_eof_trans[cs] > 0 ) {
_trans = _emoji_presentation_eof_trans[cs] - 1;
goto _eof_trans;
}
}
}
#line 94 "emoji_presentation_scanner.rl"
/* Should not be reached. */
ts = ts + 0; // suppress compilation warning.
*is_emoji = false;
return pe;
}
+171 -1
View File
@@ -35,7 +35,7 @@
/*
** Some operators to check Emoji.
** Implementation of the functions is based on some code from HarfBuzz
** (licensed under MIT).:
** (licensed under MIT):
**
** https://github.com/harfbuzz/harfbuzz
**
@@ -107,4 +107,174 @@ BOOL _unicode_is_regional_indicator(Uchar32 ch)
return (ch >= 0x1F1E6 && ch <= 0x1F1FF);
}
/*
* Implementation of EmojiIterator is based on Chromium's Ragel-based
* parser:
*
* https://chromium-review.googlesource.com/c/chromium/src/+/1264577
*
* The grammar file emoji_presentation_scanner.rl was just modified to
* adapt the function signature and variables to our usecase. The
* grammar itself was NOT modified:
*
* https://chromium-review.googlesource.com/c/chromium/src/+/1264577/3/third_party/blink/renderer/platform/fonts/emoji_presentation_scanner.rl
*
* The emoji_presentation_scanner.c is generated from .rl file by
* running ragel on it.
*
* The categorization is also based on:
*
* https://chromium-review.googlesource.com/c/chromium/src/+/1264577/3/third_party/blink/renderer/platform/fonts/utf16_ragel_iterator.h
*
* The iterator next() is based on:
*
* https://chromium-review.googlesource.com/c/chromium/src/+/1264577/3/third_party/blink/renderer/platform/fonts/symbols_iterator.cc
*
* // Copyright 2015 The Chromium Authors. All rights reserved.
* // Use of this source code is governed by a BSD-style license that can be
* // found in the LICENSE file.
*/
const Uchar32 kCombiningEnclosingCircleBackslashCharacter = 0x20E0;
const Uchar32 kCombiningEnclosingKeycapCharacter = 0x20E3;
const Uchar32 kVariationSelector15Character = 0xFE0E;
const Uchar32 kVariationSelector16Character = 0xFE0F;
const Uchar32 kZeroWidthJoinerCharacter = 0x200D;
enum EmojiScannerCategory {
EMOJI = 0,
EMOJI_TEXT_PRESENTATION = 1,
EMOJI_EMOJI_PRESENTATION = 2,
EMOJI_MODIFIER_BASE = 3,
EMOJI_MODIFIER = 4,
EMOJI_VS_BASE = 5,
REGIONAL_INDICATOR = 6,
KEYCAP_BASE = 7,
COMBINING_ENCLOSING_KEYCAP = 8,
COMBINING_ENCLOSING_CIRCLE_BACKSLASH = 9,
ZWJ = 10,
VS15 = 11,
VS16 = 12,
TAG_BASE = 13,
TAG_SEQUENCE = 14,
TAG_TERM = 15,
kMaxEmojiScannerCategory = 16
};
static unsigned char emojiSegmentationCategory (Uchar32 codepoint)
{
/* Specific ones first. */
if (codepoint == kCombiningEnclosingKeycapCharacter)
return COMBINING_ENCLOSING_KEYCAP;
if (codepoint == kCombiningEnclosingCircleBackslashCharacter)
return COMBINING_ENCLOSING_CIRCLE_BACKSLASH;
if (codepoint == kZeroWidthJoinerCharacter)
return ZWJ;
if (codepoint == kVariationSelector15Character)
return VS15;
if (codepoint == kVariationSelector16Character)
return VS16;
if (codepoint == 0x1F3F4)
return TAG_BASE;
if ((codepoint >= 0xE0030 && codepoint <= 0xE0039) ||
(codepoint >= 0xE0061 && codepoint <= 0xE007A))
return TAG_SEQUENCE;
if (codepoint == 0xE007F)
return TAG_TERM;
if (_unicode_is_emoji_modifier_base (codepoint))
return EMOJI_MODIFIER_BASE;
if (_unicode_is_emoji_modifier (codepoint))
return EMOJI_MODIFIER;
if (_unicode_is_regional_indicator (codepoint))
return REGIONAL_INDICATOR;
if (_unicode_is_emoji_keycap_base (codepoint))
return KEYCAP_BASE;
if (_unicode_is_emoji_emoji_default (codepoint))
return EMOJI_EMOJI_PRESENTATION;
if (_unicode_is_emoji_text_default (codepoint))
return EMOJI_TEXT_PRESENTATION;
if (_unicode_is_emoji (codepoint))
return EMOJI;
/* Ragel state machine will interpret unknown category as "any". */
return kMaxEmojiScannerCategory;
}
typedef BOOL bool;
enum { false = FALSE, true = TRUE };
typedef unsigned char *emoji_text_iter_t;
#include "emoji_presentation_scanner.inc"
EmojiIterator * __mg_emoji_iter_init (EmojiIterator *iter,
const Uchar32* ucs, int nr_ucs)
{
int i;
unsigned char *types;
const Uchar32 *p;
assert (nr_ucs > 0);
types = malloc (sizeof (unsigned char) * nr_ucs);
if (types == NULL)
return NULL;
p = ucs;
for (i = 0; i < nr_ucs; i++) {
types[i] = emojiSegmentationCategory (*p);
p++;
}
iter->text_start = iter->start = iter->end = ucs;
iter->text_end = ucs + nr_ucs;
iter->is_emoji = FALSE;
iter->types = types;
iter->n_chars = nr_ucs;
iter->cursor = 0;
__mg_emoji_iter_next (iter);
return iter;
}
BOOL __mg_emoji_iter_next (EmojiIterator *iter)
{
unsigned int old_cursor, cursor;
BOOL is_emoji;
if (iter->end >= iter->text_end)
return FALSE;
iter->start = iter->end;
old_cursor = cursor = iter->cursor;
cursor = scan_emoji_presentation (iter->types + cursor,
iter->types + iter->n_chars,
&is_emoji) - iter->types;
do {
iter->cursor = cursor;
iter->is_emoji = is_emoji;
if (cursor == iter->n_chars)
break;
cursor = scan_emoji_presentation (iter->types + cursor,
iter->types + iter->n_chars,
&is_emoji) - iter->types;
}
while (iter->is_emoji == is_emoji);
iter->end = iter->start + (iter->cursor - old_cursor);
return TRUE;
}
void __mg_emoji_iter_fini (EmojiIterator *iter)
{
free (iter->types);
}
#endif /* _MGCHARSET_UNICODE */
+315
View File
@@ -0,0 +1,315 @@
/*
* This file is part of MiniGUI, a mature cross-platform windowing
* and Graphics User Interface (GUI) support system for embedded systems
* and smart IoT devices.
*
* Copyright (C) 2002~2018, Beijing FMSoft Technologies Co., Ltd.
* Copyright (C) 1998~2002, WEI Yongming
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Or,
*
* As this program is a library, any link to this program must follow
* GNU General Public License version 3 (GPLv3). If you cannot accept
* GPLv3, you need to be licensed from FMSoft.
*
* If you have got a commercial license of this program, please use it
* under the terms and conditions of the commercial license.
*
* For more information about the commercial license, please refer to
* <http://www.minigui.com/en/about/licensing-policy/>.
*/
/*
** ucs-iterator.c: The implementation of the uchar string iterators.
**
** Create by WEI Yongming at 2019/03/18
**
** Implementation of WidthIterator is derived from LGPL'd Pango.
**
** Implementation of ScriptIterator is derived from ICU:
**
** icu/sources/common/usc_impl.c
**
***********************************************************************
** Copyright (C) 1999-2002, International Business Machines
** Corporation and others. All Rights Reserved.
***********************************************************************
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and associated documentation files (the
** "Software"), to deal in the Software without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, and/or sell copies of the Software, and to permit persons
** to whom the Software is furnished to do so, provided that the above
** copyright notice(s) and this permission notice appear in all copies of
** the Software and that both the above copyright notice(s) and this
** permission notice appear in supporting documentation.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
** OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
** HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
** INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
** FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
** NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
** WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**
** Except as contained in this notice, the name of a copyright holder
** shall not be used in advertising or otherwise to promote the sale, use
** or other dealings in this Software without prior written authorization
** of the copyright holder.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common.h"
#if defined(_MGCHARSET_UNICODE)
#include "minigui.h"
#include "gdi.h"
#include "unicode-ops.h"
ScriptIterator* __mg_script_iterator_init(ScriptIterator *iter,
const Uchar32* ucs, int nr_ucs)
{
assert (nr_ucs >= 0);
iter->ucs_start = ucs;
iter->ucs_end = ucs + nr_ucs;
iter->script_start = ucs;
iter->script_end = ucs;
iter->script_type = SCRIPT_COMMON;
iter->paren_sp = -1;
__mg_script_iterator_next (iter);
return iter;
}
static const Uchar32 paired_chars[] = {
0x0028, 0x0029, /* ascii paired punctuation */
0x003c, 0x003e,
0x005b, 0x005d,
0x007b, 0x007d,
0x00ab, 0x00bb, /* guillemets */
0x2018, 0x2019, /* general punctuation */
0x201c, 0x201d,
0x2039, 0x203a,
0x3008, 0x3009, /* chinese paired punctuation */
0x300a, 0x300b,
0x300c, 0x300d,
0x300e, 0x300f,
0x3010, 0x3011,
0x3014, 0x3015,
0x3016, 0x3017,
0x3018, 0x3019,
0x301a, 0x301b
};
static int get_pair_index (Uchar32 ch)
{
int lower = 0;
int upper = TABLESIZE (paired_chars) - 1;
while (lower <= upper) {
int mid = (lower + upper) / 2;
if (ch < paired_chars[mid])
upper = mid - 1;
else if (ch > paired_chars[mid])
lower = mid + 1;
else
return mid;
}
return -1;
}
#define REAL_SCRIPT(script) \
((script) > SCRIPT_INHERITED && (script) != SCRIPT_UNKNOWN)
#define SAME_SCRIPT(script1, script2) \
(!REAL_SCRIPT (script1) || !REAL_SCRIPT (script2) || (script1) == (script2))
#define IS_OPEN(pair_index) (((pair_index) & 1) == 0)
/**
* __mg_script_iterator_next:
*
* Advances a #ScriptIterator to the next range. If @iter
* is already at the end, it is left unchanged and %FALSE
* is returned.
*
* Return value: %TRUE if @iter was successfully advanced.
**/
BOOL __mg_script_iterator_next (ScriptIterator *iter)
{
int start_sp;
if (iter->script_end == iter->ucs_end)
return FALSE;
start_sp = iter->paren_sp;
iter->script_type = SCRIPT_COMMON;
iter->script_start = iter->script_end;
for (; iter->script_end < iter->ucs_end; iter->script_end++) {
Uchar32 ch = *iter->script_end;
ScriptType sc;
int pair_index;
sc = UCharGetScriptType(ch);
if (sc != SCRIPT_COMMON)
pair_index = -1;
else
pair_index = get_pair_index (ch);
/*
* Paired character handling:
*
* if it's an open character, push it onto the stack.
* if it's a close character, find the matching open on the
* stack, and use that script code. Any non-matching open
* characters above it on the stack will be poped.
*/
if (pair_index >= 0) {
if (IS_OPEN (pair_index)) {
/*
* If the paren stack is full, empty it. This
* means that deeply nested paired punctuation
* characters will be ignored, but that's an unusual
* case, and it's better to ignore them than to
* write off the end of the stack...
*/
if (++iter->paren_sp >= PAREN_STACK_DEPTH)
iter->paren_sp = 0;
iter->paren_stack[iter->paren_sp].pair_index = pair_index;
iter->paren_stack[iter->paren_sp].script_type =
iter->script_type;
}
else if (iter->paren_sp >= 0) {
int pi = pair_index & ~1;
while (iter->paren_sp >= 0 &&
iter->paren_stack[iter->paren_sp].pair_index != pi)
iter->paren_sp--;
if (iter->paren_sp < start_sp)
start_sp = iter->paren_sp;
if (iter->paren_sp >= 0)
sc = iter->paren_stack[iter->paren_sp].script_type;
}
}
if (SAME_SCRIPT (iter->script_type, sc)) {
if (!REAL_SCRIPT (iter->script_type) && REAL_SCRIPT (sc)) {
iter->script_type = sc;
/*
* now that we have a final script code, fix any open
* characters we pushed before we knew the script code.
*/
while (start_sp < iter->paren_sp)
iter->paren_stack[++start_sp].script_type =
iter->script_type;
}
/*
* if this character is a close paired character,
* pop it from the stack
*/
if (pair_index >= 0 && !IS_OPEN (pair_index) &&
iter->paren_sp >= 0) {
iter->paren_sp--;
if (iter->paren_sp < start_sp)
start_sp = iter->paren_sp;
}
}
else {
/* Different script, we're done */
break;
}
}
return TRUE;
}
static inline BOOL width_iter_is_upright(Uchar32 ch)
{
return (UCharGetVerticalOrientation(ch) == UCHAR_VOP_U);
}
void __mg_width_iter_next(WidthIterator* iter)
{
BOOL met_joiner = FALSE;
iter->start = iter->end;
if (iter->end < iter->ucs_end) {
iter->upright = width_iter_is_upright(*iter->end);
}
while (iter->end < iter->ucs_end) {
Uchar32 ch = *iter->end;
/* for zero width joiner */
if (ch == 0x200D) {
iter->end++;
met_joiner = TRUE;
continue;
}
/* ignore the upright check if met joiner */
if (met_joiner) {
iter->end++;
met_joiner = FALSE;
continue;
}
/* for variation selector, tag and emoji modifier. */
if (ch == 0xFE0EU || ch == 0xFE0FU ||
(ch >= 0xE0020 && ch <= 0xE007F) ||
(ch >= 0x1F3FB && ch <= 0x1F3FF)) {
iter->end++;
continue;
}
if (width_iter_is_upright (ch) != iter->upright)
break;
iter->end++;
}
}
WidthIterator* __mg_width_iter_init (WidthIterator* iter,
const Uchar32* ucs, int nr_ucs)
{
iter->ucs_start = ucs;
iter->ucs_end = ucs + nr_ucs;
iter->start = iter->end = ucs;
__mg_width_iter_next (iter);
return iter;
}
#endif /* _MGCHARSET_UNICODE */
+51
View File
@@ -48,6 +48,44 @@
#define UCHAR_IDSPACE 0x3000
#define UCHAR_TAB 0x0009
#define PAREN_STACK_DEPTH 128
typedef struct _ParenStackEntry {
int pair_index;
ScriptType script_type;
} ParenStackEntry;
typedef struct _ScriptIterator {
const Uchar32* ucs_start;
const Uchar32* ucs_end;
const Uchar32* script_start;
const Uchar32* script_end;
int paren_sp;
ScriptType script_type;
ParenStackEntry paren_stack[PAREN_STACK_DEPTH];
} ScriptIterator;
typedef struct _WidthIterator {
const Uchar32* ucs_start;
const Uchar32* ucs_end;
const Uchar32* start;
const Uchar32* end;
BOOL upright;
} WidthIterator;
typedef struct _EmojiIterator {
const Uchar32 *text_start;
const Uchar32 *text_end;
const Uchar32 *start;
const Uchar32 *end;
BOOL is_emoji;
unsigned char *types;
unsigned int n_chars;
unsigned int cursor;
} EmojiIterator;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
@@ -81,6 +119,19 @@ BOOL _unicode_is_emoji_emoji_default(Uchar32 ch);
BOOL _unicode_is_emoji_keycap_base(Uchar32 ch);
BOOL _unicode_is_regional_indicator(Uchar32 ch);
ScriptIterator*__mg_script_iterator_init (ScriptIterator *iter,
const Uchar32* ucs, int nr_ucs);
BOOL __mg_script_iterator_next (ScriptIterator* iter);
WidthIterator* __mg_width_iter_init (WidthIterator* iter,
const Uchar32* ucs, int nr_ucs);
void __mg_width_iter_next(WidthIterator* iter);
EmojiIterator* __mg_emoji_iter_init (EmojiIterator *iter,
const Uchar32* ucs, int nr_ucs);
BOOL __mg_emoji_iter_next (EmojiIterator *iter);
void __mg_emoji_iter_fini (EmojiIterator *iter);
#ifdef __cplusplus
}
#endif /* __cplusplus */
+2 -1
View File
@@ -17,7 +17,8 @@ SRC_FILES = gdi.c attr.c clip.c map.c coor.c rect.c \
text.c achar-uchar.c glyph.c legacy-bidi.c \
textout.c tabbedtextout.c drawtext.c \
glyph-unicode.c \
glyphruninfo.c shape-glyphs-basic.c shape-glyphs-complex.c \
glyphruninfo.c \
shape-glyphs-basic.c shape-glyphs-complex.c \
layout-shaped-glyphs.c
endif
+60 -17
View File
@@ -53,23 +53,68 @@
#include "unicode-ops.h"
#include "glyphruninfo.h"
/* Local array size, used for stack-based local arrays */
typedef enum {
EMBEDDING_CHANGED = 1 << 0,
SCRIPT_CHANGED = 1 << 1,
LANG_CHANGED = 1 << 2,
DERIVED_LANG_CHANGED = 1 << 3,
WIDTH_CHANGED = 1 << 3,
EMOJI_CHANGED = 1 << 5,
} ChangedFlags;
typedef struct _GlyphRunState {
GLYPHRUNINFO* context;
const Uchar32* text;
const Uchar32* end;
const Uchar32* run_start;
const Uchar32* run_end;
BidiLevel* embedding_levels;
const Uchar32* embedding_end;
int embedding_end_offset;
BidiLevel embedding;
GlyphOrient orient;
GlyphOrientPolicy orient_policy;
GlyphOrient resolved_gravity;
BOOL centered_baseline;
Uint8 changed;
ScriptIterator script_iter;
const Uchar32* script_end;
ScriptType script;
WidthIterator width_iter;
EmojiIterator emoji_iter;
LanguageCode derived_lang;
} GlyphRunState;
static BOOL init_glyph_runs(GLYPHRUNINFO* runinfo)
{
#if 0
BidiLevel el = runinfo->els[0];
ScriptType st = UCharGetScriptType(runinfo->ucs[0]);
#endif
return FALSE;
}
/* Local array size, used for stack-based local arrays */
#if SIZEOF_PTR == 8
# define LOCAL_ARRAY_SIZE 256
#else
# define LOCAL_ARRAY_SIZE 128
#endif
static BOOL init_glyph_runs(GLYPHRUNINFO* runinfo)
{
return FALSE;
}
GLYPHRUNINFO* GUIAPI CreateGlyphRunInfo(Uchar32* ucs, int nr_ucs,
const char* lang_tag, const char* script_tag,
GlyphRunDir run_dir, GlyphOrient glyph_orient, ParagraphDir base_dir,
Uint8 ctr, Uint8 wbr, Uint8 lbp, LOGFONT* logfont, RGBCOLOR color)
LanguageCode lang_code, ScriptType script_type,
ParagraphDir base_dir, GlyphRunDir run_dir,
GlyphOrient glyph_orient, GlyphOrientPolicy orient_policy,
Uint8 ctr, Uint8 wbr, Uint8 lbp,
LOGFONT* logfont, RGBCOLOR color)
{
BOOL ok = FALSE;
@@ -84,11 +129,8 @@ GLYPHRUNINFO* GUIAPI CreateGlyphRunInfo(Uchar32* ucs, int nr_ucs,
BidiBracketType local_brk_ts[LOCAL_ARRAY_SIZE];
BidiBracketType *brk_ts = NULL;
BidiLevel level_or, level_and;
ScriptType script_type = SCRIPT_COMMON;
int i, j;
runinfo = (GLYPHRUNINFO*)calloc(1, sizeof(GLYPHRUNINFO));
@@ -99,7 +141,7 @@ GLYPHRUNINFO* GUIAPI CreateGlyphRunInfo(Uchar32* ucs, int nr_ucs,
if (nr_ucs < LOCAL_ARRAY_SIZE)
bidi_ts = local_bidi_ts;
else
bidi_ts = malloc (nr_ucs * sizeof(BidiType));
bidi_ts = malloc(nr_ucs * sizeof(BidiType));
if (!bidi_ts) {
_DBG_PRINTF("%s: failed to allocate space for bidi types.\n");
@@ -141,6 +183,10 @@ GLYPHRUNINFO* GUIAPI CreateGlyphRunInfo(Uchar32* ucs, int nr_ucs,
}
// Initialize other fields
runinfo->ucs = ucs;
runinfo->els = els;
runinfo->bos = bos;
INIT_LIST_HEAD(&runinfo->cm_head.list);
runinfo->cm_head.si = 0;
runinfo->cm_head.len = nr_ucs;
@@ -154,7 +200,7 @@ GLYPHRUNINFO* GUIAPI CreateGlyphRunInfo(Uchar32* ucs, int nr_ucs,
runinfo->run_head.si = 0;
runinfo->run_head.nr_ucs = nr_ucs;
runinfo->run_head.lc = LanguageCodeFromISO639s1Code(lang_tag);
runinfo->run_head.lc = lang_code;
runinfo->run_head.st = script_type;
runinfo->run_head.level = BIDI_DIR_TO_LEVEL(base_dir);
runinfo->run_head.dir = run_dir;
@@ -185,9 +231,6 @@ GLYPHRUNINFO* GUIAPI CreateGlyphRunInfo(Uchar32* ucs, int nr_ucs,
goto out;
}
runinfo->ucs = ucs;
runinfo->els = els;
runinfo->bos = bos;
ok = TRUE;
out: