// Caller should acquire a lock before calling the method. // static public static FontLanguages getById(uint id) { FontLanguageListCache inst = FontLanguageListCache.getInstance(); LOG_ALWAYS_FATAL_IF(id >= inst.mLanguageLists.Count, "Lookup by unknown language list ID."); return(inst.mLanguageLists[id]); }
// Returns language list ID for the given string representation of // FontLanguages. Caller should acquire a lock before calling the method. // static public static uint getId(string languages) { FontLanguageListCache inst = FontLanguageListCache.getInstance(); Dictionary <string, uint> .Enumerator it = inst.mLanguageListLookupTable.find(languages); //C++ TO C# CONVERTER TODO TASK: Iterators are only converted within the context of 'while' and 'for' loops: if (it != inst.mLanguageListLookupTable.end()) { //C++ TO C# CONVERTER TODO TASK: Iterators are only converted within the context of 'while' and 'for' loops: return(it.second); } // Given language list is not in cache. Insert it and return newly assigned // ID. uint nextId = inst.mLanguageLists.Count; FontLanguages fontLanguages = new FontLanguages(minikin.GlobalMembers.parseLanguageList(languages)); if (fontLanguages.empty()) { return(kEmptyListId); } inst.mLanguageLists.Add(std::move(fontLanguages)); inst.mLanguageListLookupTable.Add(languages, nextId); return(nextId); }
//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#: //ORIGINAL LINE: bool isColorEmojiFamily() const; public bool isColorEmojiFamily() { FontLanguages languageList = FontLanguageListCache.getById(mLangId); for (int i = 0; i < languageList.size(); ++i) { if (languageList[i].getEmojiStyle() == FontLanguage.EMSTYLE_EMOJI) { return(true); } } return(false); }
private static FontLanguageListCache getInstance() { assertMinikinLocked(); //C++ TO C# CONVERTER NOTE: This static local variable declaration (not allowed in C#) has been moved just prior to the method: // static FontLanguageListCache* instance = null; if (getInstance_instance == null) { getInstance_instance = new FontLanguageListCache(); // Insert an empty language list for mapping default language list to // kEmptyListId. The default language list has only one FontLanguage and it // is the unsupported language. getInstance_instance.mLanguageLists.Add(new FontLanguages()); getInstance_instance.mLanguageListLookupTable.Add("", kEmptyListId); } return(getInstance_instance); }
// Lay out a single bidi run public void doLayoutRun(UInt16[] buf, int start, int count, int bufSize, bool isRtl, LayoutContext ctx, FontCollection collection) { hb_buffer_t buffer = LayoutEngine.getInstance().hbBuffer; vector <FontCollection.Run> items = new vector <FontCollection.Run>(); collection.itemize(buf + start, count, ctx.style, items); vector <hb_feature_t> features = new vector <hb_feature_t>(); // Disable default-on non-required ligature features if letter-spacing // See http://dev.w3.org/csswg/css-text-3/#letter-spacing-property // "When the effective spacing between two characters is not zero (due to // either justification or a non-zero value of letter-spacing), user agents // should not apply optional ligatures." if (Math.Abs(ctx.paint.letterSpacing) > 0.03) { hb_feature_t no_liga = new hb_feature_t(HB_TAG('l', 'i', 'g', 'a'), 0, 0, ~0u); hb_feature_t no_clig = new hb_feature_t(HB_TAG('c', 'l', 'i', 'g'), 0, 0, ~0u); features.push_back(no_liga); features.push_back(no_clig); } addFeatures(ctx.paint.fontFeatureSettings, features); double size = ctx.paint.size; double scaleX = ctx.paint.scaleX; float x = mAdvance; float y = 0F; for (int run_ix = isRtl ? items.size() - 1 : 0; isRtl?run_ix >= 0 : run_ix < (int)items.size(); isRtl ?--run_ix :++run_ix) { FontCollection.Run run = items[run_ix]; if (run.fakedFont.font == null) { ALOGE("no font for run starting u+%04x length %d", buf[run.start], run.end - run.start); continue; } int font_ix = findFace(run.fakedFont, ctx); ctx.paint.font = mFaces[font_ix].font; ctx.paint.fakery = mFaces[font_ix].fakery; HarfBuzzSharp.Font hbFont = ctx.hbFonts[font_ix]; #if VERBOSE_DEBUG ALOGD("Run %zu, font %d [%d:%d]", run_ix, font_ix, run.start, run.end); #endif hb_font_set_ppem(hbFont, size * scaleX, size); hb_font_set_scale(hbFont, HBFloatToFixed(size * scaleX), HBFloatToFixed(size)); bool is_color_bitmap_font = isColorBitmapFont(hbFont); // TODO: if there are multiple scripts within a font in an RTL run, // we need to reorder those runs. This is unlikely with our current // font stack, but should be done for correctness. // Note: scriptRunStart and scriptRunEnd, as well as run.start and run.end, // run between 0 and count. uint scriptRunEnd; for (uint scriptRunStart = run.start; scriptRunStart < run.end; scriptRunStart = scriptRunEnd) { scriptRunEnd = scriptRunStart; hb_script_t script = getScriptRun(buf + start, run.end, ref scriptRunEnd); // After the last line, scriptRunEnd is guaranteed to have increased, // since the only time getScriptRun does not increase its iterator is when // it has already reached the end of the buffer. But that can't happen, // since if we have already reached the end of the buffer, we should have // had (scriptRunEnd == run.end), which means (scriptRunStart == run.end) // which is impossible due to the exit condition of the for loop. So we // can be sure that scriptRunEnd > scriptRunStart. double letterSpace = 0.0; double letterSpaceHalfLeft = 0.0; double letterSpaceHalfRight = 0.0; if (ctx.paint.letterSpacing != 0.0 && isScriptOkForLetterspacing(new hb_script_t(script))) { letterSpace = ctx.paint.letterSpacing * size * scaleX; if ((ctx.paint.paintFlags & LinearTextFlag) == 0) { letterSpace = Math.Round(letterSpace); letterSpaceHalfLeft = Math.Floor(letterSpace * 0.5); } else { letterSpaceHalfLeft = letterSpace * 0.5; } letterSpaceHalfRight = letterSpace - letterSpaceHalfLeft; } hb_buffer_clear_contents(buffer); hb_buffer_set_script(buffer, script); hb_buffer_set_direction(buffer, isRtl ? HB_DIRECTION_RTL : HB_DIRECTION_LTR); FontLanguages langList = FontLanguageListCache.getById(ctx.style.getLanguageListId()); if (langList.size() != 0) { FontLanguage hbLanguage = langList[0]; for (int i = 0; i < langList.size(); ++i) { if (langList[i].supportsHbScript(script)) { hbLanguage = langList[i]; break; } } hb_buffer_set_language(buffer, hbLanguage.getHbLanguage()); } uint clusterStart = addToHbBuffer(buffer, new UInt16(buf), start, count, bufSize, scriptRunStart, scriptRunEnd, ctx.paint.hyphenEdit, hbFont); hb_shape(hbFont, buffer, features.empty() ? null : features[0], features.size()); uint numGlyphs; hb_glyph_info_t[] info = hb_buffer_get_glyph_infos(buffer, numGlyphs); hb_glyph_position_t positions = hb_buffer_get_glyph_positions(buffer, null); // At this point in the code, the cluster values in the info buffer // correspond to the input characters with some shift. The cluster value // clusterStart corresponds to the first character passed to HarfBuzz, // which is at buf[start + scriptRunStart] whose advance needs to be saved // into mAdvances[scriptRunStart]. So cluster values need to be reduced by // (clusterStart - scriptRunStart) to get converted to indices of // mAdvances. uint clusterOffset = clusterStart - scriptRunStart; if (numGlyphs != 0) { mAdvances[info[0].cluster - clusterOffset] += letterSpaceHalfLeft; x += letterSpaceHalfLeft; } for (uint i = 0; i < numGlyphs; i++) { #if VERBOSE_DEBUG ALOGD("%d %d %d %d", positions[i].x_advance, positions[i].y_advance, positions[i].x_offset, positions[i].y_offset); ALOGD("DoLayout %u: %f; %d, %d", info[i].codepoint, HBFixedToFloat(positions[i].x_advance), positions[i].x_offset, positions[i].y_offset); #endif if (i > 0 && info[i - 1].cluster != info[i].cluster) { mAdvances[info[i - 1].cluster - clusterOffset] += letterSpaceHalfRight; mAdvances[info[i].cluster - clusterOffset] += letterSpaceHalfLeft; x += letterSpace; } hb_codepoint_t glyph_ix = info[i].codepoint; float xoff = HBFixedToFloat(positions[i].x_offset); float yoff = -HBFixedToFloat(positions[i].y_offset); xoff += yoff * ctx.paint.skewX; LayoutGlyph glyph = new LayoutGlyph(font_ix, glyph_ix, x + xoff, y + yoff, (uint)(info[i].cluster - clusterOffset)); mGlyphs.push_back(glyph); float xAdvance = HBFixedToFloat(positions[i].x_advance); if ((ctx.paint.paintFlags & LinearTextFlag) == 0) { xAdvance = roundf(xAdvance); } MinikinRect glyphBounds = new MinikinRect(); hb_glyph_extents_t extents = new hb_glyph_extents_t(); if (is_color_bitmap_font && hb_font_get_glyph_extents(hbFont, glyph_ix, extents)) { // Note that it is technically possible for a TrueType font to have // outline and embedded bitmap at the same time. We ignore modified // bbox of hinted outline glyphs in that case. glyphBounds.mLeft = roundf(HBFixedToFloat(extents.x_bearing)); glyphBounds.mTop = roundf(HBFixedToFloat(-extents.y_bearing)); glyphBounds.mRight = roundf(HBFixedToFloat(extents.x_bearing + extents.width)); glyphBounds.mBottom = roundf(HBFixedToFloat(-extents.y_bearing - extents.height)); } else { ctx.paint.font.GetBounds(glyphBounds, glyph_ix, ctx.paint); } glyphBounds.offset(x + xoff, y + yoff); mBounds.join(glyphBounds); if ((int)(info[i].cluster - clusterOffset) < count) { mAdvances[info[i].cluster - clusterOffset] += xAdvance; } else { ALOGE("cluster %zu (start %zu) out of bounds of count %zu", info[i].cluster - clusterOffset, start, count); } x += xAdvance; } if (numGlyphs != 0) { mAdvances[info[numGlyphs - 1].cluster - clusterOffset] += letterSpaceHalfRight; x += letterSpaceHalfRight; } } } mAdvance = x; }
//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#: //ORIGINAL LINE: android::hash_t hash() const; //C++ TO C# CONVERTER TODO TASK: The implementation of the following method could not be found: // android::hash_t hash(); // Looks up a language list from an internal cache and returns its ID. // If the passed language list is not in the cache, registers it and returns // newly assigned ID. public uint registerLanguageList(string languages) { std::lock_guard <std::recursive_mutex> _l = new std::lock_guard <std::recursive_mutex>(gMinikinLock); return(FontLanguageListCache.getId(languages)); }