/* XOWA: the XOWA Offline Wiki Application Copyright (C) 2012-2017 gnosygnu@gmail.com XOWA is licensed under the terms of the General Public License (GPL) Version 3, or alternatively under the terms of the Apache License Version 2.0. You may use XOWA according to either of these licenses as is most appropriate for your project on a case-by-case basis. The terms of each license can be found in the source code repository: GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt */ package gplx.xowa.xtns.hieros; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.langs.htmls.*; import gplx.xowa.htmls.core.htmls.*; class Hiero_html_mgr { private Bry_bfr html_bfr = Bry_bfr_.Reset(Io_mgr.Len_kb), content_bfr = Bry_bfr_.Reset(255), tbl_content_bfr = Bry_bfr_.Reset(Io_mgr.Len_kb), temp_bfr = Bry_bfr_.Reset(255); private boolean cartouche_opened = false; public static int scale = 100; private Hiero_prefab_mgr prefab_mgr; private Hiero_file_mgr file_mgr; private Hiero_phoneme_mgr phoneme_mgr; private Hiero_html_wtr wtr; public Hiero_html_mgr(Hiero_xtn_mgr xtn_mgr) { prefab_mgr = xtn_mgr.Prefab_mgr(); file_mgr = xtn_mgr.File_mgr(); phoneme_mgr = xtn_mgr.Phoneme_mgr(); wtr = new Hiero_html_wtr(this, phoneme_mgr); } public void Render_blocks(Bry_bfr final_bfr, Xoh_wtr_ctx hctx, Hiero_block[] blocks, int scale, boolean hr_enabled) { wtr.Init_for_write(hctx); Hiero_html_mgr.scale = scale; tbl_content_bfr.Clear(); content_bfr.Clear(); temp_bfr.Clear(); cartouche_opened = false; if (hr_enabled) wtr.Hr(html_bfr); int blocks_len = blocks.length; for (int i = 0; i < blocks_len; i++) { Hiero_block block = blocks[i]; if (block.Len() == 1) Render_block_single(content_bfr, hctx, hr_enabled, block); else Render_block_many(content_bfr, hctx, hr_enabled, block); if (content_bfr.Len_gt_0()) tbl_content_bfr.Add_bfr_and_clear(content_bfr); // $tbl_content = $tbl + $content; } if (tbl_content_bfr.Len_gt_0()) wtr.Tbl_inner(html_bfr, tbl_content_bfr); wtr.Tbl_outer(final_bfr, html_bfr); } private void Render_block_single(Bry_bfr content_bfr, Xoh_wtr_ctx hctx, boolean hr_enabled, Hiero_block block) { byte[] code = block.Get_at(0); // block has only one code (hence the proc name: Render_block_single) byte b_0 = code[0]; switch (b_0) { case Byte_ascii.Bang: { // new_line wtr.Tbl_eol(content_bfr); if (hr_enabled) wtr.Hr(content_bfr); break; } case Byte_ascii.Lt: { // cartouche bgn wtr.Td(content_bfr, Render_glyph(hctx, Tkn_lt)); cartouche_opened = true; wtr.Cartouche_bgn(content_bfr); break; } case Byte_ascii.Gt: { // cartouche end wtr.Cartouche_end(content_bfr); cartouche_opened = false; wtr.Td(content_bfr, Render_glyph(hctx, Tkn_gt)); break; } default: { // glyph or '.' byte[] td_height = wtr.Td_height(Resize_glyph(code, cartouche_opened)); wtr.Td(content_bfr, Render_glyph(hctx, code, td_height)); break; } } } private void Render_block_many(Bry_bfr content_bfr, Xoh_wtr_ctx hctx, boolean hr_enabled, Hiero_block block) { temp_bfr.Clear(); // build prefab_bry: "convert all codes into '&' to test prefabs glyph" int block_len = block.Len(); boolean amp = false; for (int i = 0; i < block_len; i++) { byte[] v = block.Get_at(i); int v_len = v.length; amp = false; if (v_len == 1) { switch (v[0]) { case Byte_ascii.Brack_bgn: case Byte_ascii.Brack_end: case Byte_ascii.Paren_bgn: case Byte_ascii.Paren_end: case Byte_ascii.Star: case Byte_ascii.Colon: case Byte_ascii.Bang: amp = true; break; } } if (amp) temp_bfr.Add_byte(Byte_ascii.Amp); else temp_bfr.Add(v); } byte[] prefab_bry = temp_bfr.To_bry_and_clear(); Hiero_prefab_itm prefab_itm = prefab_mgr.Get_by_key(prefab_bry); if (prefab_itm != null) { byte[] td_height = wtr.Td_height(Resize_glyph(prefab_bry, cartouche_opened)); wtr.Td(content_bfr, Render_glyph(hctx, prefab_bry, td_height)); } else { int line_max = 0, total = 0, height = 0; // get block total height byte[] glyph = null; for (int i = 0; i < block_len; i++) { byte[] v = block.Get_at(i); int v_len = v.length; if (v_len == 1) { switch (v[0]) { case Byte_ascii.Colon: if (height > line_max) line_max = height; total += line_max; line_max = 0; continue; case Byte_ascii.Star: if (height > line_max) line_max = height; continue; } } Hiero_phoneme_itm phoneme_itm = phoneme_mgr.Get_by_key(v); if (phoneme_itm != null) glyph = phoneme_itm.Gardiner_code(); else glyph = v; Hiero_file_itm file_itm = file_mgr.Get_by_key(glyph); if (file_itm != null) height = 2 + file_itm.File_h(); } if (height > line_max) line_max = height; total += line_max; // render all glyph into the block for (int i = 0; i < block_len; i++) { byte[] v = block.Get_at(i); int v_len = v.length; if (v_len == 1) { switch (v[0]) { case Byte_ascii.Colon: temp_bfr.Add_str_a7("\n <br/>"); continue; case Byte_ascii.Star: temp_bfr.Add_byte_space(); continue; } } // resize the glyph according to the block total height byte[] td_height = wtr.Td_height(Resize_glyph(v, cartouche_opened, total)); temp_bfr.Add(Render_glyph(hctx, v, td_height)); } wtr.Td(content_bfr, temp_bfr.To_bry_and_clear()); } } private byte[] Render_glyph(Xoh_wtr_ctx hctx, byte[] src) {return Render_glyph(hctx, src, Bry_.Empty);} private byte[] Render_glyph(Xoh_wtr_ctx hctx, byte[] src, byte[] td_height) { int src_len = src.length; if (src_len == 0) return src; // bounds check byte byte_n = src[src_len - 1]; byte[] img_cls = byte_n == Byte_ascii.Backslash // REF.MW:isMirrored ? Bry_cls_mirrored // 'class="mw-mirrored" ' : Bry_.Empty; byte[] glyph = Extract_code(src, src_len); // trim backslashes from end; REF.MW:extractCode if (Bry_.Eq(glyph, Tkn_dot_dot)) // render void block return wtr.Void(Bool_.N); else if (Bry_.Eq(glyph, Tkn_dot)) // render 1/2 width void block return wtr.Void(Bool_.Y); else if (Bry_.Eq(glyph, Tkn_lt)) return wtr.Cartouche_img(hctx, Bool_.Y, glyph); else if (Bry_.Eq(glyph, Tkn_gt)) return wtr.Cartouche_img(hctx, Bool_.N, glyph); Hiero_phoneme_itm phoneme_itm = phoneme_mgr.Get_by_key(glyph); Hiero_file_itm file_itm = null; byte[] glyph_esc = Gfh_utl.Escape_html_as_bry(glyph); if (phoneme_itm != null) { byte[] code = phoneme_itm.Gardiner_code(); file_itm = file_mgr.Get_by_key(code); if (file_itm != null) return wtr.Img_phoneme(hctx, img_cls, td_height, glyph_esc, code); else return glyph_esc; } file_itm = file_mgr.Get_by_key(glyph); return file_itm != null ? wtr.Img_file(hctx, img_cls, td_height, glyph_esc) : glyph_esc ; } private int Resize_glyph(byte[] item, boolean cartouche_opened) {return Resize_glyph(item, cartouche_opened, 0);} private int Resize_glyph(byte[] item, boolean cartouche_opened, int total) { item = Extract_code(item, item.length); Hiero_phoneme_itm phoneme_itm = phoneme_mgr.Get_by_key(item); byte[] glyph = phoneme_itm == null ? item : phoneme_itm.Gardiner_code(); int margin = 2 * Image_margin; if (cartouche_opened) margin += 2 * (int)((Cartouche_width * scale) / 100); Hiero_file_itm file_itm = file_mgr.Get_by_key(glyph); if (file_itm != null) { int height = margin + file_itm.File_h(); if (total > 0) { return total > Max_height ? (int)(((((height * Max_height) / total) - margin) * scale) / 100) : (int)(((height - margin) * scale) / 100) ; } else { return height > Max_height ? (int)(((((Max_height * Max_height) / height) - margin) * scale) / 100) : (int)(((height - margin) * scale) / 100) ; } } return (int)(((Max_height - margin) * scale) / 100); } private static byte[] Extract_code(byte[] src, int src_len) { // trim backslashes from end; REF.MW:extractCode return Bry_.Trim_end(src, Byte_ascii.Backslash, src_len); } public static final int Image_margin = 1; public static final int Cartouche_width = 2; public static final int Max_height = 44; private static final byte[] Bry_cls_mirrored = Bry_.new_a7("class=\"mw-mirrored\" "); private static final byte[] Tkn_lt = new byte[] {Byte_ascii.Lt} , Tkn_gt = new byte[] {Byte_ascii.Gt} , Tkn_dot = new byte[] {Byte_ascii.Dot} , Tkn_dot_dot = new byte[] {Byte_ascii.Dot, Byte_ascii.Dot} ; }