void CheckMatchingPairs::check_matched_pairs(ustring & text) // Checks on matched pairs. Output any problems found. { for (unsigned int i = 0; i < text.length(); i++) { // Get the unicode character; gunichar unichar; unichar = g_utf8_get_char(text.substr(i, 1).c_str()); // If we found a mirror character, investigate further. gunichar mirror; if (g_unichar_get_mirror_char(unichar, &mirror)) { // Do we ignore this one? if (ignores.find(unichar) != ignores.end()) continue; // See whether this one opens or closes a pair. if (gopeners.find(unichar) != gopeners.end()) { // It opens: Add data. MatchingPairOpener opener(text.substr(i, 1), unichar, book, chapter, verse, get_context(text, i)); openers.push_back(opener); continue; } else { // It closes: check for previously seen opener. bool give_message = false; if (openers.empty()) { give_message = true; } if (!give_message) { if (openers[openers.size() - 1].unichar == mirror) { // Remove last one. openers.pop_back(); } else { // Flag message. give_message = true; } } if (give_message) { // Give message; message(book, chapter, verse, _("Pair not opened: ") + get_context(text, i)); } } } } }
/** * pango_get_mirror_char: * @ch: a Unicode character * @mirrored_ch: location to store the mirrored character * * If @ch has the Unicode mirrored property and there is another Unicode * character that typically has a glyph that is the mirror image of @ch's * glyph, puts that character in the address pointed to by @mirrored_ch. * * Use g_unichar_get_mirror_char() instead; the docs for that function * provide full details. * * Return value: %TRUE if @ch has a mirrored character and @mirrored_ch is * filled in, %FALSE otherwise **/ gboolean pango_get_mirror_char (gunichar ch, gunichar *mirrored_ch) { return g_unichar_get_mirror_char (ch, mirrored_ch); }
static void syriac_engine_shape (PangoEngineShape *engine, PangoFont *font, const char *text, gint length, const PangoAnalysis *analysis, PangoGlyphString *glyphs) { PangoFcFont *fc_font; FT_Face face; PangoOTRulesetDescription desc; const PangoOTRuleset *ruleset; PangoOTBuffer *buffer; gulong *properties = NULL; glong n_chars; gunichar *wcs; const char *p; int cluster = 0; int i; 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; buffer = pango_ot_buffer_new (fc_font); pango_ot_buffer_set_rtl (buffer, analysis->level % 2 != 0); pango_ot_buffer_set_zero_width_marks (buffer, TRUE); wcs = g_utf8_to_ucs4_fast (text, length, &n_chars); properties = g_new0 (gulong, n_chars); syriac_assign_properties (wcs, properties, n_chars); g_free (wcs); p = text; for (i=0; i < n_chars; i++) { gunichar wc; PangoGlyph glyph; wc = g_utf8_get_char (p); if (g_unichar_type (wc) != G_UNICODE_NON_SPACING_MARK) cluster = p - text; if (pango_is_zero_width (wc)) glyph = PANGO_GLYPH_EMPTY; else { gunichar c = wc; if (analysis->level % 2) g_unichar_get_mirror_char (c, &c); glyph = pango_fc_font_get_glyph (fc_font, c); } if (!glyph) glyph = PANGO_GET_UNKNOWN_GLYPH (wc); pango_ot_buffer_add_glyph (buffer, glyph, properties[i], cluster); p = g_utf8_next_char (p); } g_free (properties); desc.script = analysis->script; desc.language = analysis->language; desc.n_static_gsub_features = G_N_ELEMENTS (gsub_features); desc.static_gsub_features = gsub_features; desc.n_static_gpos_features = G_N_ELEMENTS (gpos_features); desc.static_gpos_features = gpos_features; /* TODO populate other_features from analysis->extra_attrs */ desc.n_other_features = 0; desc.other_features = NULL; ruleset = pango_ot_ruleset_get_for_description (pango_ot_info_get (face), &desc); pango_ot_ruleset_substitute (ruleset, buffer); pango_ot_ruleset_position (ruleset, buffer); pango_ot_buffer_output (buffer, glyphs); pango_ot_buffer_destroy (buffer); pango_fc_font_unlock_face (fc_font); }
CheckMatchingPairs::CheckMatchingPairs(const ustring & project, const vector < unsigned int >&books, const ustring & ignore, bool gui) /* It checks matching pairs of punctuation, e.g. the ( matches with the ). project: project to check. books: books to check; if empty it checks them all. ignore: punctuation to ignore. gui: whether to show graphical progressbar. */ { cancelled = false; vector < unsigned int >mybooks(books.begin(), books.end()); if (mybooks.empty()) mybooks = project_get_books(project); for (unsigned int i = 0; i < ignore.length(); i++) { gunichar unichar = g_utf8_get_char(ignore.substr(i, 1).c_str()); ignores.insert(unichar); gunichar mirror; if (g_unichar_get_mirror_char(unichar, &mirror)) { ignores.insert(mirror); } } // Get list of openers and closers. for (gunichar i = 0; i < 1000000; i++) { gunichar mirror; if (g_unichar_get_mirror_char(i, &mirror)) { if (gclosers.find(i) == gclosers.end()) { gopeners.insert(i); gclosers.insert(mirror); } } } progresswindow = NULL; if (gui) { progresswindow = new ProgressWindow(_("Matching pairs"), true); progresswindow->set_iterate(0, 1, mybooks.size()); } for (unsigned int bk = 0; bk < mybooks.size(); bk++) { book = mybooks[bk]; if (gui) { progresswindow->iterate(); if (progresswindow->cancel) { cancelled = true; break; } } vector < unsigned int >chapters = project_get_chapters(project, book); for (unsigned int ch = 0; ch < chapters.size(); ch++) { chapter = chapters[ch]; vector < ustring > verses = project_get_verses(project, book, chapter); for (unsigned int vs = 0; vs < verses.size(); vs++) { verse = verses[vs]; ustring line = project_retrieve_verse(project, book, chapter, verse); CategorizeLine categorize(line); check_matched_pairs(categorize.id); check_matched_pairs(categorize.intro); check_matched_pairs(categorize.head); check_matched_pairs(categorize.chap); check_matched_pairs(categorize.study); check_matched_pairs(categorize.note); check_matched_pairs(categorize.ref); check_matched_pairs(categorize.verse); } // At the end of each chapter, check whether all pairs are "clean" check_pairs_clean(); } } }