/* analysis->shape_engine has the PangoEngine... */ static void indic_engine_shape (PangoEngineShape *engine, PangoFont *font, const char *text, gint length, const PangoAnalysis *analysis, PangoGlyphString *glyphs) { PangoFcFont *fc_font; FT_Face face; PangoOTRuleset *gsub_ruleset, *gpos_ruleset; PangoOTBuffer *buffer; glong i, n_chars, n_glyphs; gulong *tags = NULL; gunichar *wc_in = NULL, *wc_out = NULL; glong *utf8_offsets = NULL; glong *indices = NULL; IndicEngineFc *indic_shape_engine = NULL; const PangoIndicInfo *indic_info = NULL; MPreFixups *mprefixups; g_return_if_fail (font != NULL); g_return_if_fail (text != NULL); g_return_if_fail (length >= 0); g_return_if_fail (analysis != NULL); fc_font = PANGO_FC_FONT (font); face = pango_fc_font_lock_face (fc_font); if (!face) return; indic_shape_engine = (IndicEngineFc *) engine; indic_info = indic_shape_engine->indicInfo; wc_in = expand_text (text, length, &utf8_offsets, &n_chars); n_glyphs = indic_ot_reorder (wc_in, utf8_offsets, n_chars, indic_info->classTable, NULL, NULL, NULL, NULL); wc_out = g_new (gunichar, n_glyphs); indices = g_new (glong, n_glyphs); tags = g_new (gulong, n_glyphs); n_glyphs = indic_ot_reorder (wc_in, utf8_offsets, n_chars, indic_info->classTable, wc_out, indices, tags, &mprefixups); pango_glyph_string_set_size (glyphs, n_glyphs); buffer = pango_ot_buffer_new (fc_font); set_glyphs(font, wc_out, tags, n_glyphs, buffer, (indic_info->classTable->scriptFlags & SF_PROCESS_ZWJ) != 0); /* do gsub processing */ gsub_ruleset = get_gsub_ruleset (face, indic_info); if (gsub_ruleset != NULL) pango_ot_ruleset_substitute (gsub_ruleset, buffer); /* Fix pre-modifiers for some scripts before base consonant */ if (mprefixups) { indic_mprefixups_apply (mprefixups, buffer); indic_mprefixups_free (mprefixups); } /* do gpos processing */ gpos_ruleset = get_gpos_ruleset (face, indic_info); if (gpos_ruleset != NULL) pango_ot_ruleset_position (gpos_ruleset, buffer); pango_ot_buffer_output (buffer, glyphs); /* Get the right log_clusters values */ for (i = 0; i < glyphs->num_glyphs; i += 1) glyphs->log_clusters[i] = indices[glyphs->log_clusters[i]]; pango_fc_font_unlock_face (fc_font); pango_ot_buffer_destroy (buffer); g_free (tags); g_free (indices); g_free (wc_out); g_free (wc_in); g_free (utf8_offsets); }
static bool recursive_print(std::ostream& out, const NodePtr root, const RuleTable& rules, BindingsPtr bindings, std::size_t indent, Context& context) { if (root->is_leaf()) { return !!(out << root->get_token().get_literal()); } else { Arity arity(root->size()); Operator op = root->get_op(); BindingsPtr local_bindings; RuleTable::print_iterator it, end; int found = 0; for (it = rules.reversed_find(op, arity, end); it != end; ++it) { ++found; local_bindings = std::make_shared<Bindings>(bindings); if (matches(root, it->second->get_tree_expression(), local_bindings, context)) break; } if (it == end) { // try wildcard rules for (it = rules.reversed_find(op, Arity(), end); it != end; ++it) { ++found; local_bindings = std::make_shared<Bindings>(bindings); if (matches(root, it->second->get_tree_expression(), local_bindings, context)) break; } if (it == end) { std::ostringstream os; if (found > 0) { os << "no matching "; } else { os << "no "; } os << "rule found for '" << op.get_name() << "' with " << root->size() << " parameters"; throw Exception(root->get_location(), os.str()); } } context.descend(root); const NodePtr& node = it->second->get_rhs(); std::size_t add_indent = 0; for (std::size_t pi = 0; pi < node->size(); ++pi) { const NodePtr& subnode = node->get_operand(pi); if (subnode->is_leaf()) { Token t = subnode->get_token(); switch (t.get_tokenval()) { case parser::token::TEXT_LITERAL: { expand_text(out, t, indent); int new_indent = get_indent(t.get_text()); if (new_indent >= 0) add_indent = new_indent; break; } case parser::token::VARIABLE: if (!expand_variable(out, t.get_text(), rules, indent + add_indent, bindings, local_bindings, context)) { std::ostringstream os; os << "undefined variable in replacement text: " << t.get_text(); throw Exception(subnode->get_location(), os.str()); } break; default: assert(false); std::abort(); } } else if (subnode->get_op() == Op::print_expression_listvar) { std::string varname = subnode->get_operand(0)->get_token().get_text(); if (!local_bindings->defined(varname)) { std::ostringstream os; os << "undefined variable in replacement list: " << varname; throw Exception(subnode->get_location(), os.str()); } AttributePtr list = local_bindings->get(varname); if (list->get_type() != Attribute::list) { std::ostringstream os; os << "list expected: " << varname; throw Exception(subnode->get_location(), os.str()); } if (list->size() > 0) { recursive_print(out, list->get_value(0)->get_node(), rules, bindings, indent + add_indent, context); } for (std::size_t i = 1; i < list->size(); ++i) { if (subnode->size() == 2) { Token t = subnode->get_operand(1)->get_token(); expand_text(out, t, indent); int new_indent = get_indent(t.get_text()); if (new_indent >= 0) add_indent = new_indent; } recursive_print(out, list->get_value(i)->get_node(), rules, bindings, indent + add_indent, context); } } else { assert(subnode->get_op() == Op::expression); Expression expr(subnode, local_bindings); if (!recursive_print(out, expr.convert_to_node(), rules, bindings, indent, context)) { return false; } } } } context.ascend(); return true; }