blob: a3315bbea5afb470d67abd5bd3674f1f569000a8 [file] [log] [blame]
Behdad Esfahbod15232e22009-08-13 17:13:25 -04001/*
2 * Copyright (C) 2009 Red Hat, Inc.
3 *
Behdad Esfahbodc755cb32010-04-22 00:11:43 -04004 * This is part of HarfBuzz, a text shaping library.
Behdad Esfahbod15232e22009-08-13 17:13:25 -04005 *
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
11 *
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 *
24 * Red Hat Author(s): Behdad Esfahbod
25 */
26
27#include "hb-private.h"
28
29#include "hb-shape.h"
30
Behdad Esfahbod2f50d872009-11-04 21:07:03 -050031#include "hb-buffer-private.h"
32
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +010033#include "hb-ot-shape-private.h"
34
Behdad Esfahbod26d7a752009-12-20 17:58:25 +010035
36/* Prepare */
37
Behdad Esfahbod2f50d872009-11-04 21:07:03 -050038static inline hb_bool_t
39is_variation_selector (hb_codepoint_t unicode)
40{
Behdad Esfahbodd33f6742009-11-18 09:47:44 -050041 return HB_UNLIKELY ((unicode >= 0x180B && unicode <= 0x180D) || /* MONGOLIAN FREE VARIATION SELECTOR ONE..THREE */
42 (unicode >= 0xFE00 && unicode <= 0xFE0F) || /* VARIATION SELECTOR-1..16 */
43 (unicode >= 0xE0100 && unicode <= 0xE01EF)); /* VARIATION SELECTOR-17..256 */
Behdad Esfahbod2f50d872009-11-04 21:07:03 -050044}
45
46static void
Behdad Esfahbodff44f882009-11-06 19:48:16 -050047hb_form_clusters (hb_buffer_t *buffer)
48{
49 unsigned int count;
50
51 count = buffer->in_length;
52 for (buffer->in_pos = 1; buffer->in_pos < count; buffer->in_pos++)
53 if (buffer->unicode->get_general_category (IN_CURGLYPH()) == HB_CATEGORY_NON_SPACING_MARK)
54 IN_CLUSTER (buffer->in_pos) = IN_CLUSTER (buffer->in_pos - 1);
55}
56
Behdad Esfahbod001fc2d2009-12-20 17:24:05 +010057static hb_direction_t
58hb_ensure_native_direction (hb_buffer_t *buffer)
59{
60 hb_direction_t original_direction = buffer->direction;
61
62 /* TODO vertical */
63 if (HB_DIRECTION_IS_HORIZONTAL (original_direction) &&
64 original_direction != _hb_script_get_horizontal_direction (buffer->script))
65 {
66 hb_buffer_reverse_clusters (buffer);
67 buffer->direction ^= 1;
68 }
69
70 return original_direction;
71}
72
Behdad Esfahbod26d7a752009-12-20 17:58:25 +010073
74/* Substitute */
75
Behdad Esfahbod001fc2d2009-12-20 17:24:05 +010076static void
77hb_mirror_chars (hb_buffer_t *buffer)
78{
79 unsigned int count;
80 hb_unicode_get_mirroring_func_t get_mirroring = buffer->unicode->get_mirroring;
81
82 if (HB_DIRECTION_IS_FORWARD (buffer->direction))
83 return;
84
85 count = buffer->in_length;
86 for (buffer->in_pos = 0; buffer->in_pos < count; buffer->in_pos++) {
87 IN_CURGLYPH() = get_mirroring (IN_CURGLYPH());
88 }
89}
90
Behdad Esfahbodff44f882009-11-06 19:48:16 -050091static void
Behdad Esfahbod2027f742009-11-05 16:34:47 -050092hb_map_glyphs (hb_font_t *font,
93 hb_face_t *face,
94 hb_buffer_t *buffer)
Behdad Esfahbod2f50d872009-11-04 21:07:03 -050095{
96 unsigned int count;
97
Behdad Esfahbod51f141a2009-12-20 18:22:28 +010098 if (HB_UNLIKELY (!buffer->in_length))
99 return;
Behdad Esfahbod2f50d872009-11-04 21:07:03 -0500100 count = buffer->in_length - 1;
Behdad Esfahbod2f50d872009-11-04 21:07:03 -0500101 for (buffer->in_pos = 0; buffer->in_pos < count; buffer->in_pos++) {
102 if (HB_UNLIKELY (is_variation_selector (IN_NEXTGLYPH()))) {
Behdad Esfahbod9bef3612009-11-05 12:20:11 -0500103 IN_CURGLYPH() = hb_font_get_glyph (font, face, IN_CURGLYPH(), IN_NEXTGLYPH());
Behdad Esfahbod2f50d872009-11-04 21:07:03 -0500104 buffer->in_pos++;
105 } else {
Behdad Esfahbod9bef3612009-11-05 12:20:11 -0500106 IN_CURGLYPH() = hb_font_get_glyph (font, face, IN_CURGLYPH(), 0);
Behdad Esfahbod2f50d872009-11-04 21:07:03 -0500107 }
108 }
Behdad Esfahbod9bef3612009-11-05 12:20:11 -0500109 IN_CURGLYPH() = hb_font_get_glyph (font, face, IN_CURGLYPH(), 0);
Behdad Esfahbod2f50d872009-11-04 21:07:03 -0500110}
111
Behdad Esfahbod2027f742009-11-05 16:34:47 -0500112static void
Behdad Esfahbod26d7a752009-12-20 17:58:25 +0100113hb_substitute_default (hb_font_t *font,
114 hb_face_t *face,
Behdad Esfahbod196610b2009-12-20 19:01:14 +0100115 hb_buffer_t *buffer,
116 hb_feature_t *features,
117 unsigned int num_features)
Behdad Esfahbod26d7a752009-12-20 17:58:25 +0100118{
119 hb_mirror_chars (buffer);
120 hb_map_glyphs (font, face, buffer);
121}
122
Behdad Esfahbod2f78c172009-12-20 21:03:11 +0100123static hb_bool_t
Behdad Esfahbod26d7a752009-12-20 17:58:25 +0100124hb_substitute_complex (hb_font_t *font,
125 hb_face_t *face,
Behdad Esfahbod196610b2009-12-20 19:01:14 +0100126 hb_buffer_t *buffer,
127 hb_feature_t *features,
128 unsigned int num_features)
Behdad Esfahbod26d7a752009-12-20 17:58:25 +0100129{
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100130 return _hb_ot_substitute_complex (font, face, buffer, features, num_features);
Behdad Esfahbod26d7a752009-12-20 17:58:25 +0100131}
132
133static void
134hb_substitute_fallback (hb_font_t *font,
135 hb_face_t *face,
Behdad Esfahbod196610b2009-12-20 19:01:14 +0100136 hb_buffer_t *buffer,
137 hb_feature_t *features,
138 unsigned int num_features)
Behdad Esfahbod26d7a752009-12-20 17:58:25 +0100139{
140 /* TODO Arabic */
141}
142
143
144/* Position */
145
146static void
Behdad Esfahbod2027f742009-11-05 16:34:47 -0500147hb_position_default (hb_font_t *font,
148 hb_face_t *face,
Behdad Esfahbod196610b2009-12-20 19:01:14 +0100149 hb_buffer_t *buffer,
150 hb_feature_t *features,
151 unsigned int num_features)
Behdad Esfahbod2027f742009-11-05 16:34:47 -0500152{
153 unsigned int count;
154
155 hb_buffer_clear_positions (buffer);
156
157 count = buffer->in_length;
Behdad Esfahbod2027f742009-11-05 16:34:47 -0500158 for (buffer->in_pos = 0; buffer->in_pos < count; buffer->in_pos++) {
159 hb_glyph_metrics_t metrics;
160 hb_font_get_glyph_metrics (font, face, IN_CURGLYPH(), &metrics);
161 CURPOSITION()->x_advance = metrics.x_advance;
162 CURPOSITION()->y_advance = metrics.y_advance;
163 }
164}
165
Behdad Esfahbod2f78c172009-12-20 21:03:11 +0100166static hb_bool_t
Behdad Esfahbod26d7a752009-12-20 17:58:25 +0100167hb_position_complex (hb_font_t *font,
168 hb_face_t *face,
Behdad Esfahbod196610b2009-12-20 19:01:14 +0100169 hb_buffer_t *buffer,
170 hb_feature_t *features,
171 unsigned int num_features)
Behdad Esfahbod26d7a752009-12-20 17:58:25 +0100172{
Behdad Esfahbod2014b8d2009-12-20 20:58:26 +0100173 return _hb_ot_position_complex (font, face, buffer, features, num_features);
Behdad Esfahbod26d7a752009-12-20 17:58:25 +0100174}
175
176static void
177hb_position_fallback (hb_font_t *font,
178 hb_face_t *face,
Behdad Esfahbod196610b2009-12-20 19:01:14 +0100179 hb_buffer_t *buffer,
180 hb_feature_t *features,
181 unsigned int num_features)
Behdad Esfahbod26d7a752009-12-20 17:58:25 +0100182{
183 /* TODO Mark pos */
184}
185
Behdad Esfahbod6a2ef5a2009-12-20 16:28:01 +0100186static void
Behdad Esfahbod001fc2d2009-12-20 17:24:05 +0100187hb_truetype_kern (hb_font_t *font,
188 hb_face_t *face,
Behdad Esfahbod196610b2009-12-20 19:01:14 +0100189 hb_buffer_t *buffer,
190 hb_feature_t *features,
191 unsigned int num_features)
Behdad Esfahbod6a2ef5a2009-12-20 16:28:01 +0100192{
193 unsigned int count;
Behdad Esfahbod6a2ef5a2009-12-20 16:28:01 +0100194
Behdad Esfahbod196610b2009-12-20 19:01:14 +0100195 /* TODO Check for kern=0 */
Behdad Esfahbod6a2ef5a2009-12-20 16:28:01 +0100196 count = buffer->in_length;
Behdad Esfahbod001fc2d2009-12-20 17:24:05 +0100197 for (buffer->in_pos = 1; buffer->in_pos < count; buffer->in_pos++) {
198 hb_position_t kern, kern1, kern2;
199 kern = hb_font_get_kerning (font, face, IN_GLYPH(buffer->in_pos - 1), IN_CURGLYPH());
200 kern1 = kern >> 1;
201 kern2 = kern - kern1;
202 POSITION(buffer->in_pos - 1)->x_advance += kern1;
203 CURPOSITION()->x_advance += kern2;
204 CURPOSITION()->x_offset += kern2;
Behdad Esfahbod6a2ef5a2009-12-20 16:28:01 +0100205 }
206}
207
Behdad Esfahbod26d7a752009-12-20 17:58:25 +0100208static void
209hb_position_fallback_visual (hb_font_t *font,
210 hb_face_t *face,
Behdad Esfahbod196610b2009-12-20 19:01:14 +0100211 hb_buffer_t *buffer,
212 hb_feature_t *features,
213 unsigned int num_features)
Behdad Esfahbod26d7a752009-12-20 17:58:25 +0100214{
Behdad Esfahbod196610b2009-12-20 19:01:14 +0100215 hb_truetype_kern (font, face, buffer, features, num_features);
Behdad Esfahbod26d7a752009-12-20 17:58:25 +0100216}
217
218
219/* Shape */
220
Behdad Esfahbod15232e22009-08-13 17:13:25 -0400221void
Behdad Esfahbod9bef3612009-11-05 12:20:11 -0500222hb_shape (hb_font_t *font,
223 hb_face_t *face,
Behdad Esfahbod15232e22009-08-13 17:13:25 -0400224 hb_buffer_t *buffer,
225 hb_feature_t *features,
226 unsigned int num_features)
227{
Behdad Esfahbodff44f882009-11-06 19:48:16 -0500228 hb_direction_t original_direction;
Behdad Esfahbod26d7a752009-12-20 17:58:25 +0100229 hb_bool_t substitute_fallback, position_fallback;
Behdad Esfahbodff44f882009-11-06 19:48:16 -0500230
231 hb_form_clusters (buffer);
232 original_direction = hb_ensure_native_direction (buffer);
233
Behdad Esfahbod196610b2009-12-20 19:01:14 +0100234 hb_substitute_default (font, face, buffer, features, num_features);
Behdad Esfahbod6a2ef5a2009-12-20 16:28:01 +0100235
Behdad Esfahbod196610b2009-12-20 19:01:14 +0100236 substitute_fallback = !hb_substitute_complex (font, face, buffer, features, num_features);
Behdad Esfahbod15232e22009-08-13 17:13:25 -0400237
Behdad Esfahbod26d7a752009-12-20 17:58:25 +0100238 if (substitute_fallback)
Behdad Esfahbod196610b2009-12-20 19:01:14 +0100239 hb_substitute_fallback (font, face, buffer, features, num_features);
Behdad Esfahbod1ff77752009-11-06 13:52:57 -0500240
Behdad Esfahbod196610b2009-12-20 19:01:14 +0100241 hb_position_default (font, face, buffer, features, num_features);
Behdad Esfahbod1ff77752009-11-06 13:52:57 -0500242
Behdad Esfahbod196610b2009-12-20 19:01:14 +0100243 position_fallback = !hb_position_complex (font, face, buffer, features, num_features);
Behdad Esfahbod26d7a752009-12-20 17:58:25 +0100244
245 if (position_fallback)
Behdad Esfahbod196610b2009-12-20 19:01:14 +0100246 hb_position_fallback (font, face, buffer, features, num_features);
Behdad Esfahbodff44f882009-11-06 19:48:16 -0500247
Behdad Esfahbod314b4602009-12-20 13:58:50 +0100248 if (HB_DIRECTION_IS_BACKWARD (buffer->direction))
Behdad Esfahbod4a860532009-11-06 19:52:01 -0500249 hb_buffer_reverse (buffer);
250
Behdad Esfahbod26d7a752009-12-20 17:58:25 +0100251 if (position_fallback)
Behdad Esfahbod196610b2009-12-20 19:01:14 +0100252 hb_position_fallback_visual (font, face, buffer, features, num_features);
Behdad Esfahbod001fc2d2009-12-20 17:24:05 +0100253
Behdad Esfahbod4a860532009-11-06 19:52:01 -0500254 buffer->direction = original_direction;
Behdad Esfahbod2f50d872009-11-04 21:07:03 -0500255}