public void GetNext(out char c, out bool inHL) { if (runPos >= runTxt.Length) { ++runIX; runPos = 0; if (runIX < txt.RunCount) { runTxt = txt.GetRunAt(runIX).GetPlainText(); } else { runTxt = null; } } if (runTxt == null) { c = (char)0; inHL = false; return; } c = runTxt[runPos]; if (hl == null || hl.RunIx != runIX) { inHL = false; } else { inHL = runPos >= hl.HiliteStart && runPos < hl.HiliteStart + hl.HiliteLength; } ++runPos; }
/// <summary> /// Converts a hybrid text to CEDICT-formatted plain text (marking up hanzi+pinyin sections). /// </summary> public static string HybridToCedict(HybridText ht) { StringBuilder sb = new StringBuilder(); bool first = true; for (int i = 0; i != ht.RunCount; ++i) { TextRun tr = ht.GetRunAt(i); if (tr is TextRunLatin) { string strRun = tr.GetPlainText(); if (!first && strRun != string.Empty && !char.IsPunctuation(strRun[0])) { sb.Append(' '); } sb.Append(strRun); } else { if (!first) { sb.Append(' '); } TextRunZho trz = tr as TextRunZho; if (!string.IsNullOrEmpty(trz.Simp)) { sb.Append(trz.Simp); } if (trz.Trad != trz.Simp && !string.IsNullOrEmpty(trz.Trad)) { sb.Append('|'); sb.Append(trz.Trad); } if (trz.Pinyin != null) { sb.Append('['); sb.Append(GetPinyinCedict(trz.Pinyin)); sb.Append(']'); } } first = false; } return(sb.ToString()); }
/// <summary> /// Returns true if display font covers all Hanzi in hybrid text; false otherwise. /// </summary> private bool areHanziCovered(HybridText ht) { if (ht.IsEmpty) { return(true); } for (int i = 0; i != ht.RunCount; ++i) { TextRun tr = ht.GetRunAt(i); TextRunZho trJoe = tr as TextRunZho; if (trJoe == null) { continue; } if (trJoe.Simp == null) { continue; } foreach (char c in trJoe.Simp) { if (!cvr.GetCoverage(c).HasFlag(FontCoverageFlags.Simp)) { return(false); } } if (trJoe.Trad == null) { continue; } foreach (char c in trJoe.Trad) { if (!cvr.GetCoverage(c).HasFlag(FontCoverageFlags.Trad)) { return(false); } } } return(true); }
/// <summary> /// <para>Produces unmeasured display blocks from a single hybrid text. Marks highlights, if any.</para> /// <para>Does not fill in blocks' size, but fills in everything else.</para> /// </summary> /// <param name="htxt">Hybrid text to break down into blocks and measure.</param> /// <param name="isMeta">True if this is a domain or note (displayed in italics).</param> /// <param name="hl">Highlight to show in hybrid text, or null.</param> /// <param name="blocks">List of blocks to append to.</param> /// <param name="links">List to gather links (appending to list).</param> private void makeBlocks(HybridText htxt, bool isMeta, CedictTargetHighlight hl, List<Block> blocks, List<LinkArea> links) { byte fntIdxLatin = isMeta ? fntMetaLatin : fntSenseLatin; byte fntIdxZhoSimp = isMeta ? fntMetaHanziSimp : fntSenseHanziSimp; byte fntIdxZhoTrad = isMeta ? fntMetaHanziTrad : fntSenseHanziTrad; // Go run by run for (int runIX = 0; runIX != htxt.RunCount; ++runIX) { TextRun run = htxt.GetRunAt(runIX); // Latin run: split by spaces first if (run is TextRunLatin) { string[] bySpaces = run.GetPlainText().Split(new char[] { ' ' }); // Each word: also by dash int latnPos = 0; foreach (string str in bySpaces) { string[] byDashes = splitByDash(str); // Add block for each int ofsPos = 0; foreach (string blockStr in byDashes) { Block tb = new Block { TextPos = textPool.PoolString(blockStr), FontIdx = fntIdxLatin, SpaceAfter = false, // will set this true for last block in "byDashes" }; // Does block's text intersect with highlight? if (hl != null && hl.RunIx == runIX) { int blockStart = latnPos + ofsPos; int blockEnd = blockStart + blockStr.Length; if (blockStart >= hl.HiliteStart && blockStart < hl.HiliteStart + hl.HiliteLength) tb.Hilite = true; else if (blockEnd > hl.HiliteStart && blockEnd <= hl.HiliteStart + hl.HiliteLength) tb.Hilite = true; else if (blockStart < hl.HiliteStart && blockEnd >= hl.HiliteStart + hl.HiliteLength) tb.Hilite = true; } blocks.Add(tb); // Keep track of position for highlight ofsPos += blockStr.Length; } // Make sure last one is followed by space Block xb = blocks[blocks.Count - 1]; xb.SpaceAfter = true; blocks[blocks.Count - 1] = xb; // Keep track of position in text - for highlights latnPos += str.Length + 1; } } // Chinese: depends on T/S/Both display mode, and on available info else { TextRunZho zhoRun = run as TextRunZho; // Chinese range is made up of: // Simplified (empty string if only traditional requested) // Separator (if both simplified and traditional are requested) // Traditional (empty string if only simplified requested) // Pinyin with accents as tone marks, in brackets (if present) string strSimp = string.Empty; if (analyzedScript != SearchScript.Traditional && zhoRun.Simp != null) strSimp = zhoRun.Simp; string strTrad = string.Empty; if (analyzedScript != SearchScript.Simplified && zhoRun.Trad != null) strTrad = zhoRun.Trad; string strPy = string.Empty; // Convert pinyin to display format (tone marks as diacritics; r5 glued) if (zhoRun.Pinyin != null) strPy = "[" + zhoRun.GetPinyinInOne(true) + "]"; // Create link area, with query string string strPyNumbers = string.Empty; // Pinyin with numbers as tone marks if (zhoRun.Pinyin != null) strPyNumbers = zhoRun.GetPinyinRaw(); LinkArea linkArea = new LinkArea(strSimp, strTrad, strPyNumbers, analyzedScript); // Block for simplified, if present if (strSimp != string.Empty) { Block tb = new Block { TextPos = textPool.PoolString(strSimp), FontIdx = fntIdxZhoSimp, SpaceAfter = true, }; blocks.Add(tb); linkArea.BlockIds.Add(blocks.Count - 1); } // Separator if both simplified and traditional are there // AND they are different... if (strSimp != string.Empty && strTrad != string.Empty && strSimp != strTrad) { Block xb = blocks[blocks.Count - 1]; xb.StickRight = true; blocks[blocks.Count - 1] = xb; Block tb = new Block { TextPos = textPool.PoolString("•"), FontIdx = fntIdxLatin, SpaceAfter = true, }; blocks.Add(tb); linkArea.BlockIds.Add(blocks.Count - 1); } // Traditional, if present if (strTrad != string.Empty && strTrad != strSimp) { Block tb = new Block { TextPos = textPool.PoolString(strTrad), FontIdx = fntIdxZhoTrad, SpaceAfter = true, }; blocks.Add(tb); linkArea.BlockIds.Add(blocks.Count - 1); } // Pinyin, if present if (strPy != string.Empty) { // Split by spaces string[] pyParts = strPy.Split(new char[] { ' ' }); foreach (string pyPart in pyParts) { Block tb = new Block { TextPos = textPool.PoolString(pyPart), FontIdx = fntIdxLatin, SpaceAfter = true, }; blocks.Add(tb); linkArea.BlockIds.Add(blocks.Count - 1); } } // Last part will have requested a space after. // Look ahead and if next text run is Latin and starts with punctuation, make it stick TextRunLatin nextLatinRun = null; if (runIX + 1 < htxt.RunCount) nextLatinRun = htxt.GetRunAt(runIX + 1) as TextRunLatin; if (nextLatinRun != null && char.IsPunctuation(nextLatinRun.GetPlainText()[0])) { Block xb = blocks[blocks.Count - 1]; xb.SpaceAfter = false; blocks[blocks.Count - 1] = xb; } // Collect link area links.Add(linkArea); } } }
/// <summary> /// Converts a hybrid text to HTML (marking up hanzi+pinyin sections). /// </summary> public static string HybridToHtml(HybridText ht, SearchScript script) { StringBuilder sb = new StringBuilder(); bool first = true; for (int i = 0; i != ht.RunCount; ++i) { TextRun tr = ht.GetRunAt(i); if (tr is TextRunLatin) { string strRun = tr.GetPlainText(); if (!first && strRun != string.Empty && !char.IsPunctuation(strRun[0])) { sb.Append(' '); } sb.Append(strRun); } else { if (!first) { sb.Append(' '); } TextRunZho trz = tr as TextRunZho; string hanzi1 = (script == SearchScript.Traditional) ? trz.Trad : trz.Simp; if (string.IsNullOrEmpty(hanzi1)) { hanzi1 = null; } string hanzi2 = null; if (hanzi1 != null && script == SearchScript.Both && !string.IsNullOrEmpty(trz.Trad)) { hanzi2 = trz.Trad; } if (hanzi1 != null) { hanzi1 = escape(hanzi1); } if (hanzi2 != null) { hanzi2 = escape(hanzi2); } if (hanzi1 != null || hanzi2 != null) { sb.Append(templateSenseHanziOpen); } if (hanzi1 != null) { sb.Append(hanzi1); } if (hanzi2 != null) { sb.Append(' '); sb.Append(templateBullet); sb.Append(' '); sb.Append(hanzi2); } if (hanzi1 != null || hanzi2 != null) { sb.Append(templateSenseHanziClose); } if (trz.Pinyin != null) { if (hanzi1 != null) { sb.Append(' '); } sb.Append('['); sb.Append(escape(trz.GetPinyinInOne(true))); sb.Append(']'); } } first = false; } return(sb.ToString()); }
/// <summary> /// Converts a hybrid text to HTML (marking up hanzi+pinyin sections). /// </summary> public static string HybridToHtml(HybridText ht, SearchScript script) { StringBuilder sb = new StringBuilder(); bool first = true; for (int i = 0; i != ht.RunCount; ++i) { TextRun tr = ht.GetRunAt(i); if (tr is TextRunLatin) { string strRun = tr.GetPlainText(); if (!first && strRun != string.Empty && !char.IsPunctuation(strRun[0])) sb.Append(' '); sb.Append(strRun); } else { if (!first) sb.Append(' '); TextRunZho trz = tr as TextRunZho; string hanzi1 = (script == SearchScript.Traditional) ? trz.Trad : trz.Simp; if (string.IsNullOrEmpty(hanzi1)) hanzi1 = null; string hanzi2 = null; if (hanzi1 != null && script == SearchScript.Both && !string.IsNullOrEmpty(trz.Trad)) hanzi2 = trz.Trad; if (hanzi1 != null) hanzi1 = escape(hanzi1); if (hanzi2 != null) hanzi2 = escape(hanzi2); if (hanzi1 != null || hanzi2 != null) sb.Append(templateSenseHanziOpen); if (hanzi1 != null) sb.Append(hanzi1); if (hanzi2 != null) { sb.Append(' '); sb.Append(templateBullet); sb.Append(' '); sb.Append(hanzi2); } if (hanzi1 != null || hanzi2 != null) sb.Append(templateSenseHanziClose); if (trz.Pinyin != null) { if (hanzi1 != null) sb.Append(' '); sb.Append('['); sb.Append(escape(trz.GetPinyinInOne(true))); sb.Append(']'); } } first = false; } return sb.ToString(); }
/// <summary> /// Converts a hybrid text to CEDICT-formatted plain text (marking up hanzi+pinyin sections). /// </summary> public static string HybridToCedict(HybridText ht) { StringBuilder sb = new StringBuilder(); bool first = true; for (int i = 0; i != ht.RunCount; ++i) { TextRun tr = ht.GetRunAt(i); if (tr is TextRunLatin) { string strRun = tr.GetPlainText(); if (!first && strRun != string.Empty && !char.IsPunctuation(strRun[0])) sb.Append(' '); sb.Append(strRun); } else { if (!first) sb.Append(' '); TextRunZho trz = tr as TextRunZho; if (!string.IsNullOrEmpty(trz.Simp)) sb.Append(trz.Simp); if (trz.Trad != trz.Simp && !string.IsNullOrEmpty(trz.Trad)) { sb.Append('|'); sb.Append(trz.Trad); } if (trz.Pinyin != null) { sb.Append('['); sb.Append(GetPinyinCedict(trz.Pinyin)); sb.Append(']'); } } first = false; } return sb.ToString(); }
/// <summary> /// Returns true if display font covers all Hanzi in hybrid text; false otherwise. /// </summary> private bool areHanziCovered(HybridText ht) { if (ht.IsEmpty) return true; for (int i = 0; i != ht.RunCount; ++i) { TextRun tr = ht.GetRunAt(i); TextRunZho trJoe = tr as TextRunZho; if (trJoe == null) continue; if (trJoe.Simp == null) continue; foreach (char c in trJoe.Simp) if (!cvr.GetCoverage(c).HasFlag(FontCoverageFlags.Simp)) return false; if (trJoe.Trad == null) continue; foreach (char c in trJoe.Trad) if (!cvr.GetCoverage(c).HasFlag(FontCoverageFlags.Trad)) return false; } return true; }
public HybridTextConsumer(HybridText txt, CedictTargetHighlight hl) { this.txt = txt; this.hl = hl; runTxt = txt.GetRunAt(0).GetPlainText(); }
/// <summary> /// <para>Produces unmeasured display blocks from a single hybrid text. Marks highlights, if any.</para> /// <para>Does not fill in blocks' size, but fills in everything else.</para> /// </summary> /// <param name="htxt">Hybrid text to break down into blocks and measure.</param> /// <param name="isMeta">True if this is a domain or note (displayed in italics).</param> /// <param name="hl">Highlight to show in hybrid text, or null.</param> /// <param name="blocks">List of blocks to append to.</param> /// <param name="links">List to gather links (appending to list).</param> private void makeBlocks(HybridText htxt, bool isMeta, CedictTargetHighlight hl, List <Block> blocks, List <LinkArea> links) { byte fntIdxLatin = isMeta ? fntMetaLatin : fntSenseLatin; byte fntIdxZhoSimp = isMeta ? fntMetaHanziSimp : fntSenseHanziSimp; byte fntIdxZhoTrad = isMeta ? fntMetaHanziTrad : fntSenseHanziTrad; // Go run by run for (int runIX = 0; runIX != htxt.RunCount; ++runIX) { TextRun run = htxt.GetRunAt(runIX); // Latin run: split by spaces first if (run is TextRunLatin) { string[] bySpaces = run.GetPlainText().Split(new char[] { ' ' }); // Each word: also by dash int latnPos = 0; foreach (string str in bySpaces) { string[] byDashes = splitByDash(str); // Add block for each int ofsPos = 0; foreach (string blockStr in byDashes) { Block tb = new Block { TextPos = textPool.PoolString(blockStr), FontIdx = fntIdxLatin, SpaceAfter = false, // will set this true for last block in "byDashes" }; // Does block's text intersect with highlight? if (hl != null && hl.RunIx == runIX) { int blockStart = latnPos + ofsPos; int blockEnd = blockStart + blockStr.Length; if (blockStart >= hl.HiliteStart && blockStart < hl.HiliteStart + hl.HiliteLength) { tb.Hilite = true; } else if (blockEnd > hl.HiliteStart && blockEnd <= hl.HiliteStart + hl.HiliteLength) { tb.Hilite = true; } else if (blockStart < hl.HiliteStart && blockEnd >= hl.HiliteStart + hl.HiliteLength) { tb.Hilite = true; } } blocks.Add(tb); // Keep track of position for highlight ofsPos += blockStr.Length; } // Make sure last one is followed by space Block xb = blocks[blocks.Count - 1]; xb.SpaceAfter = true; blocks[blocks.Count - 1] = xb; // Keep track of position in text - for highlights latnPos += str.Length + 1; } } // Chinese: depends on T/S/Both display mode, and on available info else { TextRunZho zhoRun = run as TextRunZho; // Chinese range is made up of: // Simplified (empty string if only traditional requested) // Separator (if both simplified and traditional are requested) // Traditional (empty string if only simplified requested) // Pinyin with accents as tone marks, in brackets (if present) string strSimp = string.Empty; if (analyzedScript != SearchScript.Traditional && zhoRun.Simp != null) { strSimp = zhoRun.Simp; } string strTrad = string.Empty; if (analyzedScript != SearchScript.Simplified && zhoRun.Trad != null) { strTrad = zhoRun.Trad; } string strPy = string.Empty; // Convert pinyin to display format (tone marks as diacritics; r5 glued) if (zhoRun.Pinyin != null) { strPy = "[" + zhoRun.GetPinyinInOne(true) + "]"; } // Create link area, with query string string strPyNumbers = string.Empty; // Pinyin with numbers as tone marks if (zhoRun.Pinyin != null) { strPyNumbers = zhoRun.GetPinyinRaw(); } LinkArea linkArea = new LinkArea(strSimp, strTrad, strPyNumbers, analyzedScript); // Block for simplified, if present if (strSimp != string.Empty) { Block tb = new Block { TextPos = textPool.PoolString(strSimp), FontIdx = fntIdxZhoSimp, SpaceAfter = true, }; blocks.Add(tb); linkArea.BlockIds.Add(blocks.Count - 1); } // Separator if both simplified and traditional are there // AND they are different... if (strSimp != string.Empty && strTrad != string.Empty && strSimp != strTrad) { Block xb = blocks[blocks.Count - 1]; xb.StickRight = true; blocks[blocks.Count - 1] = xb; Block tb = new Block { TextPos = textPool.PoolString("•"), FontIdx = fntIdxLatin, SpaceAfter = true, }; blocks.Add(tb); linkArea.BlockIds.Add(blocks.Count - 1); } // Traditional, if present if (strTrad != string.Empty && strTrad != strSimp) { Block tb = new Block { TextPos = textPool.PoolString(strTrad), FontIdx = fntIdxZhoTrad, SpaceAfter = true, }; blocks.Add(tb); linkArea.BlockIds.Add(blocks.Count - 1); } // Pinyin, if present if (strPy != string.Empty) { // Split by spaces string[] pyParts = strPy.Split(new char[] { ' ' }); foreach (string pyPart in pyParts) { Block tb = new Block { TextPos = textPool.PoolString(pyPart), FontIdx = fntIdxLatin, SpaceAfter = true, }; blocks.Add(tb); linkArea.BlockIds.Add(blocks.Count - 1); } } // Last part will have requested a space after. // Look ahead and if next text run is Latin and starts with punctuation, make it stick TextRunLatin nextLatinRun = null; if (runIX + 1 < htxt.RunCount) { nextLatinRun = htxt.GetRunAt(runIX + 1) as TextRunLatin; } if (nextLatinRun != null && char.IsPunctuation(nextLatinRun.GetPlainText()[0])) { Block xb = blocks[blocks.Count - 1]; xb.SpaceAfter = false; blocks[blocks.Count - 1] = xb; } // Collect link area links.Add(linkArea); } } }