summaryrefslogtreecommitdiff
path: root/source/fitz
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2016-01-29 14:10:53 +0000
committerRobin Watts <robin.watts@artifex.com>2016-02-04 13:21:11 +0000
commitd96bd69b94c12906473a4721c2c2dc5941923253 (patch)
tree6101971a4f96dbb5a6c4d189e1dd8ae5cf62cbcf /source/fitz
parent5d840271f62c5a51bb83d561181de860086bb6be (diff)
downloadmupdf-d96bd69b94c12906473a4721c2c2dc5941923253.tar.xz
Make HTML layout use harfbuzz for shaping.
fz_fonts gain a 'shaper' field that will be filled in as required. Use a void * rather than an hb_font_t to avoid polluting top level include space. Harfbuff handles mirroring for us, so lose the 'mirror' fields. This simplifies our wrappers around the 'standard' bidi code in that we don't need to split fragments upon mirroring. We do need to split our fragments at script changes though as harfbuzz only operates on a single font at a time. Update the html flow structure so that each flow node contains details of the the direction specified for it in the markup, the language specified for it in the markup and the script detected by the bidi code. Get the bidi code to pass out the script for each fragment as part of the callback and populate that field in the node. Ensure that we pass in the markup direction to the bidi splitting code as the 'base' direction. When feeding the bidi code, rather than feeding it paragraphs at a time, break those paragraphs if different parts of them have different marked up directions.
Diffstat (limited to 'source/fitz')
-rw-r--r--source/fitz/bidi.c165
-rw-r--r--source/fitz/font.c4
2 files changed, 80 insertions, 89 deletions
diff --git a/source/fitz/bidi.c b/source/fitz/bidi.c
index e711e705..74548d4d 100644
--- a/source/fitz/bidi.c
+++ b/source/fitz/bidi.c
@@ -205,76 +205,83 @@ is_european_number(const uint32_t *str, unsigned int len)
return TRUE;
}
+/* Split fragments into single scripts (or punctation + single script) */
static void
-do_callback(const uint32_t *fragment,
+split_at_script(const uint32_t *fragment,
size_t fragment_len,
int block_r2l,
- uint32_t mirror,
+ int char_r2l,
void *arg,
fz_bidi_fragment_callback *callback)
{
- char char_r2l = block_r2l;
+ int script = UCDN_SCRIPT_COMMON;
+ size_t script_start, i;
- char_r2l = block_r2l && !is_european_number(fragment, fragment_len);
-
- (*callback)(fragment, fragment_len, block_r2l, char_r2l, mirror, arg);
-}
-
-/* Searches a RTL fragment for a mirror character
- * When it finds one it creates a separate fragment for the
- * character and the surrounding fragments. It passes the mirrored
- * character back through the callback.
- */
-static void
-create_fragment_mirrors(const uint32_t *text,
- int len,
- fz_bidi_fragment_callback *callback,
- void *arg)
-{
- int i;
- int lastPtr;
- uint32_t mirror;
-
- assert(text != NULL);
- assert(len > 0);
- lastPtr = 0;
- for (i = 0; i < len; i ++)
+ script_start = 0;
+ for (i = 0; i < fragment_len; i++)
{
- mirror = ucdn_mirror(text[i]);
- if (mirror != UNICODE_EOS)
+ int s = ucdn_get_script(fragment[i]);
+ if (s == UCDN_SCRIPT_COMMON || s == UCDN_SCRIPT_INHERITED)
{
- /* create preceding fragment */
- if (i > lastPtr)
- {
- do_callback(&text[lastPtr],
- i - lastPtr,
- TRUE,
- UNICODE_EOS,
- arg,
- callback);
- DBUGVF(("create mirror fragment for %x\n",(int)text[i]));
- }
- /* create mirror fragment */
- do_callback(&text[i],
- 1,
- TRUE,
- mirror,
- arg,
- callback);
- lastPtr = i + 1;
+ /* Punctuation etc. This is fine. */
+ }
+ else if (s == script)
+ {
+ /* Same script. Still fine. */
+ }
+ else if (script == UCDN_SCRIPT_COMMON || script == UCDN_SCRIPT_INHERITED)
+ {
+ /* First non punctuation thing. Set the script. */
+ script = s;
}
+ else
+ {
+ /* Change of script. Break the fragment. */
+ (*callback)(&fragment[script_start], i - script_start, block_r2l, char_r2l, script, arg);
+ script_start = i+1;
+ script = s;
+ }
+ }
+ if (script_start != fragment_len)
+ {
+ (*callback)(&fragment[script_start], fragment_len - script_start, block_r2l, char_r2l, script, arg);
}
+}
+
+static void
+detect_numbers(const uint32_t *fragment,
+ size_t fragment_len,
+ size_t start,
+ size_t end,
+ const fz_bidi_level *levels,
+ void *arg,
+ fz_bidi_fragment_callback *callback)
+{
+ int block_r2l = ODD(levels[start]);
+ int char_r2l = block_r2l;
- if (lastPtr < len)
+ /* Check to see if we've got a number. Numbers should
+ * never be block_r2l, so we can avoid the test. */
+ if (block_r2l || !is_european_number(&fragment[start], end-start))
{
- /* create end fragment */
- do_callback(&text[lastPtr],
- len - lastPtr,
- TRUE,
- UNICODE_EOS,
+ /* No number, just split as normal */
+ split_at_script(&fragment[start],
+ end-start,
+ block_r2l,
+ char_r2l,
arg,
callback);
+ return;
}
+
+ /* We have a number. We have to check to see whether this
+ * should be handled as a block_r2l thing. */
+ if (start != 0)
+ block_r2l = ODD(levels[start-1]);
+ if (block_r2l && end != fragment_len)
+ block_r2l = ODD(levels[end]);
+
+ split_at_script(&fragment[start], end-start, block_r2l, char_r2l, arg, callback);
}
/* Determines the character classes for all following
@@ -607,45 +614,25 @@ void fz_bidi_fragment_text(fz_context *ctx,
* Create a text object for it, then start
* a new fragment.
*/
- if (ODD(levels[startOfFragment]) != 0)
- {
- /* if RTL check for mirrors and create sub-frags */
- create_fragment_mirrors(&text[startOfFragment],
- i - startOfFragment,
- callback,
- arg);
- }
- else
- {
- do_callback(&text[startOfFragment],
- i - startOfFragment,
- ODD(levels[startOfFragment]),
- UNICODE_EOS,
- arg,
- callback);
- }
+ detect_numbers(text,
+ textlen,
+ startOfFragment,
+ i,
+ levels,
+ arg,
+ callback);
startOfFragment = i;
}
}
/* Now i == textlen. Deal with the final (or maybe only) fragment. */
- if (ODD(levels[startOfFragment]) != 0)
- {
- /* if RTL check for mirrors and create sub-frags */
- create_fragment_mirrors(&text[startOfFragment],
- i - startOfFragment,
- callback,
- arg);
- }
- else
- {
- /* otherwise create 1 fragment */
- do_callback(&text[startOfFragment],
- i - startOfFragment,
- ODD(levels[startOfFragment]),
- UNICODE_EOS,
- arg,
- callback);
- }
+ /* otherwise create 1 fragment */
+ detect_numbers(text,
+ textlen,
+ startOfFragment,
+ i,
+ levels,
+ arg,
+ callback);
}
fz_always(ctx)
{
diff --git a/source/fitz/font.c b/source/fitz/font.c
index a7db05d4..e7dbc827 100644
--- a/source/fitz/font.c
+++ b/source/fitz/font.c
@@ -1,6 +1,9 @@
#include "mupdf/fitz.h"
#include <ft2build.h>
+#include "hb.h"
+#include "hb-ft.h"
+
#include FT_FREETYPE_H
#include FT_ADVANCES_H
#include FT_STROKER_H
@@ -150,6 +153,7 @@ fz_drop_font(fz_context *ctx, fz_font *font)
fz_free(ctx, font->bbox_table);
fz_free(ctx, font->width_table);
fz_free(ctx, font->advance_cache);
+ hb_font_destroy(font->shaper);
fz_free(ctx, font);
}