Explicitly constify a bunch of static data declarations which were
[sgt/halibut] / bk_paper.c
index b38060f..aed648c 100644 (file)
@@ -199,31 +199,31 @@ static paper_conf paper_configure(paragraph *source, font_list *fontlist) {
     /*
      * Defaults.
      */
-    ret.paper_width = 595 * 4096;
-    ret.paper_height = 841 * 4096;
-    ret.left_margin = 72 * 4096;
-    ret.top_margin = 72 * 4096;
-    ret.right_margin = 72 * 4096;
-    ret.bottom_margin = 108 * 4096;
-    ret.indent_list_bullet = 6 * 4096;
-    ret.indent_list_after = 18 * 4096;
-    ret.indent_quote = 18 * 4096;
-    ret.base_leading = 4096;
-    ret.base_para_spacing = 10 * 4096;
-    ret.chapter_top_space = 72 * 4096;
-    ret.sect_num_left_space = 12 * 4096;
-    ret.chapter_underline_depth = 14 * 4096;
-    ret.chapter_underline_thickness = 3 * 4096;
-    ret.rule_thickness = 1 * 4096;
+    ret.paper_width = 595 * UNITS_PER_PT;
+    ret.paper_height = 841 * UNITS_PER_PT;
+    ret.left_margin = 72 * UNITS_PER_PT;
+    ret.top_margin = 72 * UNITS_PER_PT;
+    ret.right_margin = 72 * UNITS_PER_PT;
+    ret.bottom_margin = 108 * UNITS_PER_PT;
+    ret.indent_list_bullet = 6 * UNITS_PER_PT;
+    ret.indent_list_after = 18 * UNITS_PER_PT;
+    ret.indent_quote = 18 * UNITS_PER_PT;
+    ret.base_leading = UNITS_PER_PT;
+    ret.base_para_spacing = 10 * UNITS_PER_PT;
+    ret.chapter_top_space = 72 * UNITS_PER_PT;
+    ret.sect_num_left_space = 12 * UNITS_PER_PT;
+    ret.chapter_underline_depth = 14 * UNITS_PER_PT;
+    ret.chapter_underline_thickness = 3 * UNITS_PER_PT;
+    ret.rule_thickness = 1 * UNITS_PER_PT;
     ret.base_font_size = 12;
-    ret.contents_indent_step = 24 * 4096;
-    ret.contents_margin = 84 * 4096;
-    ret.leader_separation = 12 * 4096;
-    ret.index_gutter = 36 * 4096;
+    ret.contents_indent_step = 24 * UNITS_PER_PT;
+    ret.contents_margin = 84 * UNITS_PER_PT;
+    ret.leader_separation = 12 * UNITS_PER_PT;
+    ret.index_gutter = 36 * UNITS_PER_PT;
     ret.index_cols = 2;
-    ret.index_minsep = 18 * 4096;
+    ret.index_minsep = 18 * UNITS_PER_PT;
     ret.pagenum_fontsize = 12;
-    ret.footer_distance = 32 * 4096;
+    ret.footer_distance = 32 * UNITS_PER_PT;
     ret.lquote = L"\x2018\0\x2019\0'\0'\0\0";
     ret.rquote = uadv(ret.lquote);
     ret.bullet = L"\x2022\0-\0\0";
@@ -257,70 +257,70 @@ static paper_conf paper_configure(paragraph *source, font_list *fontlist) {
                ret.bullet = uadv(p->keyword);
            } else if (!ustricmp(p->keyword, L"paper-page-width")) {
                ret.paper_width =
-                   (int) 0.5 + 4096.0 * utof(uadv(p->keyword));
+                   (int) 0.5 + FUNITS_PER_PT * utof(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-page-height")) {
                ret.paper_height =
-                   (int) 0.5 + 4096.0 * utof(uadv(p->keyword));
+                   (int) 0.5 + FUNITS_PER_PT * utof(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-left-margin")) {
                ret.left_margin =
-                   (int) 0.5 + 4096.0 * utof(uadv(p->keyword));
+                   (int) 0.5 + FUNITS_PER_PT * utof(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-top-margin")) {
                ret.top_margin =
-                   (int) 0.5 + 4096.0 * utof(uadv(p->keyword));
+                   (int) 0.5 + FUNITS_PER_PT * utof(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-right-margin")) {
                ret.right_margin =
-                   (int) 0.5 + 4096.0 * utof(uadv(p->keyword));
+                   (int) 0.5 + FUNITS_PER_PT * utof(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-bottom-margin")) {
                ret.bottom_margin =
-                   (int) 0.5 + 4096.0 * utof(uadv(p->keyword));
+                   (int) 0.5 + FUNITS_PER_PT * utof(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-list-indent")) {
                ret.indent_list_bullet =
-                   (int) 0.5 + 4096.0 * utof(uadv(p->keyword));
+                   (int) 0.5 + FUNITS_PER_PT * utof(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-listitem-indent")) {
                ret.indent_list =
-                   (int) 0.5 + 4096.0 * utof(uadv(p->keyword));
+                   (int) 0.5 + FUNITS_PER_PT * utof(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-quote-indent")) {
                ret.indent_quote =
-                   (int) 0.5 + 4096.0 * utof(uadv(p->keyword));
+                   (int) 0.5 + FUNITS_PER_PT * utof(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-base-leading")) {
                ret.base_leading =
-                   (int) 0.5 + 4096.0 * utof(uadv(p->keyword));
+                   (int) 0.5 + FUNITS_PER_PT * utof(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-base-para-spacing")) {
                ret.base_para_spacing =
-                   (int) 0.5 + 4096.0 * utof(uadv(p->keyword));
+                   (int) 0.5 + FUNITS_PER_PT * utof(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-chapter-top-space")) {
                ret.chapter_top_space =
-                   (int) 0.5 + 4096.0 * utof(uadv(p->keyword));
+                   (int) 0.5 + FUNITS_PER_PT * utof(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-sect-num-left-space")) {
                ret.sect_num_left_space =
-                   (int) 0.5 + 4096.0 * utof(uadv(p->keyword));
+                   (int) 0.5 + FUNITS_PER_PT * utof(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-chapter-underline-depth")) {
                ret.chapter_underline_depth =
-                   (int) 0.5 + 4096.0 * utof(uadv(p->keyword));
+                   (int) 0.5 + FUNITS_PER_PT * utof(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-chapter-underline-thickness")) {
                ret.chapter_underline_thickness =
-                   (int) 0.5 + 4096.0 * utof(uadv(p->keyword));
+                   (int) 0.5 + FUNITS_PER_PT * utof(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-rule-thickness")) {
                ret.rule_thickness =
-                   (int) 0.5 + 4096.0 * utof(uadv(p->keyword));
+                   (int) 0.5 + FUNITS_PER_PT * utof(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-contents-indent-step")) {
                ret.contents_indent_step =
-                   (int) 0.5 + 4096.0 * utof(uadv(p->keyword));
+                   (int) 0.5 + FUNITS_PER_PT * utof(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-contents-margin")) {
                ret.contents_margin =
-                   (int) 0.5 + 4096.0 * utof(uadv(p->keyword));
+                   (int) 0.5 + FUNITS_PER_PT * utof(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-leader-separation")) {
                ret.leader_separation =
-                   (int) 0.5 + 4096.0 * utof(uadv(p->keyword));
+                   (int) 0.5 + FUNITS_PER_PT * utof(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-index-gutter")) {
                ret.index_gutter =
-                   (int) 0.5 + 4096.0 * utof(uadv(p->keyword));
+                   (int) 0.5 + FUNITS_PER_PT * utof(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-index-minsep")) {
                ret.index_minsep =
-                   (int) 0.5 + 4096.0 * utof(uadv(p->keyword));
+                   (int) 0.5 + FUNITS_PER_PT * utof(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-footer-distance")) {
                ret.footer_distance =
-                   (int) 0.5 + 4096.0 * utof(uadv(p->keyword));
+                   (int) 0.5 + FUNITS_PER_PT * utof(uadv(p->keyword));
            } else if (!ustricmp(p->keyword, L"paper-base-font-size")) {
                ret.base_font_size =
                    utoi(uadv(p->keyword));
@@ -1248,16 +1248,34 @@ static font_encoding *new_font_encoding(font_data *font)
     return fe;
 }
 
+static int kern_cmp(void *a, void *b)
+{
+    kern_pair const *ka = a, *kb = b;
+
+    if (ka->left < kb->left)
+       return -1;
+    if (ka->left > kb->left)
+       return 1;
+    if (ka->right < kb->right)
+       return -1;
+    if (ka->right > kb->right)
+       return 1;
+    return 0;
+}
+
 static font_data *make_std_font(font_list *fontlist, char const *name)
 {
     const int *widths;
+    const kern_pair *kerns;
     int nglyphs;
     font_data *f;
     font_encoding *fe;
     int i;
 
+    /* XXXKERN */
     widths = ps_std_font_widths(name);
-    if (!widths)
+    kerns = ps_std_font_kerns(name);
+    if (!widths || !kerns)
        return NULL;
 
     for (nglyphs = 0; ps_std_glyphs[nglyphs] != NULL; nglyphs++);
@@ -1269,6 +1287,9 @@ static font_data *make_std_font(font_list *fontlist, char const *name)
     f->nglyphs = nglyphs;
     f->glyphs = ps_std_glyphs;
     f->widths = widths;
+    f->kerns = newtree234(kern_cmp);
+    for (;kerns->left != 0xFFFF; kerns++)
+       add234(f->kerns, (void *)kerns);
     f->subfont_map = snewn(nglyphs, subfont_map_entry);
 
     /*
@@ -1308,23 +1329,42 @@ static font_data *make_std_font(font_list *fontlist, char const *name)
     return f;
 }
 
+/* NB: arguments are glyph numbers from font->bmp. */
+static int find_kern(font_data *font, int lindex, int rindex)
+{
+    kern_pair wantkp;
+    kern_pair const *kp;
+
+    if (lindex == 0xFFFF || rindex == 0xFFFF)
+       return 0;
+    wantkp.left = lindex;
+    wantkp.right = rindex;
+    kp = find234(font->kerns, &wantkp, NULL);
+    if (kp == NULL)
+       return 0;
+    return kp->kern;
+}
+
 static int string_width(font_data *font, wchar_t const *string, int *errs)
 {
     int width = 0;
+    int index, oindex;
 
     if (errs)
        *errs = 0;
 
+    oindex = 0xFFFF;
     for (; *string; string++) {
-       int index;
+       index = (*string < 0 || *string > 0xFFFF ? 0xFFFF :
+                font->bmp[*string]);
 
-       index = font->bmp[(unsigned short)*string];
        if (index == 0xFFFF) {
            if (errs)
                *errs = 1;
        } else {
-           width += font->widths[index];
+           width += find_kern(font, oindex, index) + font->widths[index];
        }
+       oindex = index;
     }
 
     return width;
@@ -1431,7 +1471,7 @@ static void wrap_paragraph(para_data *pdata, word *words,
        for (i = 0; i < NFONTS; i++)
            if (line_height < pdata->sizes[i])
                line_height = pdata->sizes[i];
-       line_height *= 4096;
+       line_height *= UNITS_PER_PT;
     }
 
     spacewidth = (pdata->sizes[FONT_NORMAL] *
@@ -1442,7 +1482,7 @@ static void wrap_paragraph(para_data *pdata, word *words,
         * comes up, but I'll make a random guess anyway and set my
         * space width to half the point size.
         */
-       spacewidth = pdata->sizes[FONT_NORMAL] * 4096 / 2;
+       spacewidth = pdata->sizes[FONT_NORMAL] * UNITS_PER_PT / 2;
     }
 
     /*
@@ -1602,7 +1642,8 @@ static page_data *page_breaks(line_data *first, line_data *last,
                     */
                    if (m != last && m->next && !m->next->page_break)
                    {
-                       int x = this_height - minheight;
+                       int x = (this_height - minheight) / FUNITS_PER_PT *
+                           4096.0;
                        int xf;
 
                        xf = x & 0xFF;
@@ -1691,9 +1732,11 @@ static page_data *page_breaks(line_data *first, line_data *last,
            text += l->line_height;
 
            l->page = page;
-           l->ypos = text + space + head +
-               space * (float)page->first_line->vshortfall[n] /
-               page->first_line->space[n];
+           l->ypos = text + space + head;
+           if (page->first_line->space[n]) {
+               l->ypos += space * (float)page->first_line->vshortfall[n] /
+                   page->first_line->space[n];
+           }
 
            if (l == page->last_line)
                break;
@@ -1757,14 +1800,17 @@ static int render_string(page_data *page, font_data *font, int fontsize,
                         int x, int y, wchar_t *str)
 {
     char *text;
-    int textpos, textwid, glyph;
+    int textpos, textwid, kern, glyph, oglyph;
     font_encoding *subfont = NULL, *sf;
 
     text = snewn(1 + ustrlen(str), char);
     textpos = textwid = 0;
 
+    glyph = 0xFFFF;
     while (*str) {
-       glyph = font->bmp[*str];
+       oglyph = glyph;
+       glyph = (*str < 0 || *str > 0xFFFF ? 0xFFFF :
+                font->bmp[*str]);
 
        if (glyph == 0xFFFF) {
            str++;
@@ -1798,16 +1844,19 @@ static int render_string(page_data *page, font_data *font, int fontsize,
            sf = font->latest_subfont;
        }
 
-       if (!subfont || sf != subfont) {
+       kern = find_kern(font, oglyph, glyph) * fontsize;
+
+       if (!subfont || sf != subfont || kern) {
            if (subfont) {
                text[textpos] = '\0';
                add_string_to_page(page, x, y, subfont, fontsize, text,
                                   textwid);
-               x += textwid;
+               x += textwid + kern;
            } else {
                assert(textpos == 0);
            }
            textpos = 0;
+           textwid = 0;
            subfont = sf;
        }
 
@@ -2309,7 +2358,7 @@ static para_data *code_paragraph(int indent, word *words, paper_conf *conf)
        ldata->pdata = pdata;
        ldata->first = lhead;
        ldata->end = NULL;
-       ldata->line_height = conf->base_font_size * 4096;
+       ldata->line_height = conf->base_font_size * UNITS_PER_PT;
 
        ldata->xpos = indent;