public void set(MinikinRect r) { mLeft = r.mLeft; mTop = r.mTop; mRight = r.mRight; mBottom = r.mBottom; }
// Append another layout (for example, cached value) into this one public void appendLayout(Layout src, int start, float extraAdvance) { int[] fontMapStack = new int[16]; //C++ TO C# CONVERTER TODO TASK: C# does not have an equivalent to pointers to value types: //ORIGINAL LINE: int* fontMap; int fontMap; //C++ TO C# CONVERTER WARNING: This 'sizeof' ratio was replaced with a direct reference to the array length: //ORIGINAL LINE: if (src->mFaces.size() < sizeof(fontMapStack) / sizeof(fontMapStack[0])) if (src.mFaces.size() < fontMapStack.Length) { fontMap = fontMapStack; } else { fontMap = new int[src.mFaces.size()]; } for (int i = 0; i < src.mFaces.size(); i++) { int font_ix = findFace(src.mFaces[i], null); fontMap[i] = font_ix; } // LibTxt: Changed x0 from int to float to prevent rounding that causes text // jitter. float x0 = mAdvance; for (int i = 0; i < src.mGlyphs.size(); i++) { LayoutGlyph srcGlyph = src.mGlyphs[i]; int font_ix = fontMap[srcGlyph.font_ix]; uint glyph_id = srcGlyph.glyph_id; float x = x0 + srcGlyph.x; float y = srcGlyph.y; LayoutGlyph glyph = new LayoutGlyph(font_ix, glyph_id, x, y, (uint)(srcGlyph.cluster + start)); mGlyphs.push_back(glyph); } for (int i = 0; i < src.mAdvances.size(); i++) { mAdvances[i + start] = src.mAdvances[i]; if (i == 0) { mAdvances[i + start] += extraAdvance; } } MinikinRect srcBounds = new MinikinRect(src.mBounds); srcBounds.offset(x0, 0); mBounds.join(srcBounds); mAdvance += src.mAdvance + extraAdvance; if (fontMap != fontMapStack) { fontMap = null; } }
public void join(MinikinRect r) { if (isEmpty()) { set(r); } else if (!r.isEmpty()) { mLeft = Math.Min(mLeft, r.mLeft); mTop = Math.Min(mTop, r.mTop); mRight = Math.Max(mRight, r.mRight); mBottom = Math.Max(mBottom, r.mBottom); } }
// 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: void getBounds(MinikinRect* rect) const; public void getBounds(MinikinRect bounds) { bounds.set(mBounds); }
//C++ TO C# CONVERTER WARNING: 'const' methods are not available in C#: //ORIGINAL LINE: virtual void GetBounds(MinikinRect* bounds, uint glyph_id, const MinikinPaint& paint) const = 0; public abstract void GetBounds(MinikinRect bounds, uint glyph_id, MinikinPaint paint);