]> granicus.if.org Git - libass/blob - libass/ass_shaper.c
Provisional bidi and shaping support
[libass] / libass / ass_shaper.c
1 /*
2  * Copyright (C) 2011 Grigori Goronzy <greg@chown.ath.cx>
3  *
4  * This file is part of libass.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18
19 #include <fribidi/fribidi.h>
20
21 #include "ass_render.h"
22 #include "ass_shaper.h"
23
24 /**
25  * \brief Shape an event's text. Calculates directional runs and shapes them.
26  * \param text_info event's text
27  * \param ctypes returns character types
28  * \param emblevels returns embedding levels (directional runs)
29  */
30 void ass_shaper_shape(TextInfo *text_info, FriBidiCharType *ctypes,
31                       FriBidiLevel *emblevels)
32 {
33     int i, last_break;
34     FriBidiParType dir;
35     FriBidiChar *event_text = calloc(sizeof(*event_text), text_info->length);
36     GlyphInfo *glyphs = text_info->glyphs;
37
38     // Get bidi character types and embedding levels
39     last_break = 0;
40     for (i = 0; i < text_info->length; i++) {
41         event_text[i] = glyphs[i].symbol;
42         // embedding levels should be calculated paragraph by paragraph
43         if (glyphs[i].symbol == '\n' || i == text_info->length - 1) {
44             //printf("paragraph from %d to %d\n", last_break, i);
45             dir = FRIBIDI_PAR_ON;
46             fribidi_get_bidi_types(event_text + last_break, i - last_break + 1,
47                     ctypes + last_break);
48             fribidi_get_par_embedding_levels(ctypes + last_break,
49                     i - last_break + 1, &dir, emblevels + last_break);
50             last_break = i + 1;
51         }
52     }
53
54 #if 0
55     printf("levels ");
56     for (i = 0; i < text_info->length; i++) {
57         printf("%d:%d ", ctypes[i], emblevels[i]);
58     }
59     printf("\n");
60 #endif
61
62     // Call FriBidi's glyph mirroring shaper.
63     // This shaper implements rule L4 of the bidi algorithm
64     fribidi_shape_mirroring(emblevels, text_info->length, event_text);
65     for (i = 0; i < text_info->length; i++) {
66         glyphs[i].symbol = event_text[i];
67     }
68
69     // XXX: insert HarfBuzz shaper here
70
71     // Skip direction override characters
72     // NOTE: Behdad said HarfBuzz is supposed to remove these, but this hasn't
73     // been implemented yet
74     for (i = 0; i < text_info->length; i++) {
75         if (glyphs[i].symbol <= 0x202F && glyphs[i].symbol >= 0x202a) {
76             glyphs[i].symbol = 0;
77             glyphs[i].skip++;
78         }
79     }
80
81     free(event_text);
82 }
83
84 void ass_shaper_reorder(TextInfo *text_info, FriBidiCharType *ctypes,
85                         FriBidiLevel *emblevels, FriBidiStrIndex *cmap)
86 {
87     int i;
88     FriBidiParType dir = FRIBIDI_PAR_LTR;
89
90     // Initialize reorder map
91     for (i = 0; i < text_info->length; i++)
92         cmap[i] = i;
93
94     // Create reorder map line-by-line
95     for (i = 0; i < text_info->n_lines; i++) {
96         LineInfo *line = text_info->lines + i;
97         int level;
98
99         // FIXME: we should actually specify
100         // the correct paragraph base direction
101         level = fribidi_reorder_line(FRIBIDI_FLAGS_DEFAULT,
102                 ctypes + line->offset, line->len, 0, dir,
103                 emblevels + line->offset, NULL, cmap + line->offset);
104         //printf("reorder line %d to level %d\n", i, level);
105     }
106
107 #if 0
108     printf("map ");
109     for (i = 0; i < text_info->length; i++) {
110         printf("%d ", cmap[i]);
111     }
112     printf("\n");
113 #endif
114
115 }