bool CSSInlineLayoutRenderLayerInline::node(CSSInlineGeneratedBox *cur) { CSSBoxNode *node = cur->box_node; CSSBoxText *text = dynamic_cast<CSSBoxText*>(node); if (text) { const CSSComputedValues &properties = text->get_properties(); if (properties.get_misc_inherit().visibility.type == CSSValueVisibility::type_visible) { Font font = graphics->get_font(properties); FontMetrics metrics = graphics->get_font_metrics(font); int pos_x = used_to_actual(cur->relative_x) + formatting_context->get_x(); int pos_y = used_to_actual(cur->relative_y) + formatting_context->get_y(); graphics->draw_text(font, pos_x + cur->x, pos_y + cur->y + used_to_actual(metrics.get_ascent()), text->processed_text.substr(cur->text_start, cur->text_end - cur->text_start), properties.get_text_inherit().color.color); } } else if (cur->layout_node) { CSSLayoutTreeNode *object_node = cur->layout_node; bool is_same_stacking_context = (stacking_context == object_node->get_stacking_context()); bool is_positioned = (object_node->get_element_node()->computed_values.get_box().position.type != CSSValuePosition::type_static); if (is_same_stacking_context && !is_positioned) object_node->render_layer_inline(graphics, resources); } return true; }
Size Font::get_text_size(Canvas &canvas, const std::string &text) { Size total_size; if (impl) { FontMetrics fm = get_font_metrics(); int line_spacing = fm.get_external_leading(); std::vector<std::string> lines = StringHelp::split_text(text, "\n", false); for (std::vector<std::string>::size_type i=0; i<lines.size(); i++) { Size line_size = impl->get_text_size(canvas, lines[i]); if ((line_size.width == 0) && (line_size.height == 0) && (lines.size() > 1)) // blank line line_size.height = fm.get_descent() + fm.get_ascent(); if ((i+1) != lines.size()) // Do not add the line spacing on the last line line_size.height += line_spacing; if (total_size.width < line_size.width) // Find the widest line total_size.width = line_size.width; total_size.height += line_size.height; } } return total_size; }
void Font::draw_text_ellipsis(Canvas &canvas, float dest_x, float dest_y, Rectf content_box, const std::string &text, const Colorf &color) { if (impl) { FontMetrics fm = get_font_metrics(); int ascent = fm.get_ascent(); int descent = fm.get_descent(); int line_spacing = fm.get_height() + fm.get_external_leading(); std::vector<std::string> lines = StringHelp::split_text(text, "\n", false); for (std::vector<std::string>::size_type i=0; i<lines.size(); i++) { if (i == 0 || (dest_y - ascent >= content_box.top && dest_y + descent < content_box.bottom)) { Size size = get_text_size(canvas, lines[i]); if (dest_x + size.width <= content_box.right) { draw_text(canvas, dest_x, dest_y, lines[i], color); } else { Size ellipsis = get_text_size(canvas, "..."); int seek_start = 0; int seek_end = lines[i].size(); int seek_center = (seek_start + seek_end) / 2; UTF8_Reader utf8_reader(lines[i].data(), lines[i].length()); while (true) { utf8_reader.set_position(seek_center); utf8_reader.move_to_leadbyte(); if (seek_center != utf8_reader.get_position()) utf8_reader.next(); seek_center = utf8_reader.get_position(); if (seek_center == seek_end) break; utf8_reader.set_position(seek_start); utf8_reader.next(); if (utf8_reader.get_position() == seek_end) break; Size text_size = get_text_size(canvas, lines[i].substr(0, seek_center)); if (dest_x + text_size.width + ellipsis.width >= content_box.right) seek_end = seek_center; else seek_start = seek_center; seek_center = (seek_start+seek_end)/2; } draw_text(canvas, dest_x, dest_y, lines[i].substr(0, seek_center) + "...", color); } dest_y += line_spacing; } } } }
static inline float positionOffsetForDecoration(TextDecoration decoration, const FontMetrics& fontMetrics, float thickness) { // FIXME: For SVG Fonts we need to use the attributes defined in the <font-face> if specified. // Compatible with Batik/Opera. if (decoration == TextDecorationUnderline) return fontMetrics.floatAscent() + thickness * 1.5f; if (decoration == TextDecorationOverline) return thickness; if (decoration == TextDecorationLineThrough) return fontMetrics.floatAscent() * 5 / 8.0f; ASSERT_NOT_REACHED(); return 0.0f; }
static inline float positionOffsetForDecoration(ETextDecoration decoration, const FontMetrics& fontMetrics, float thickness) { // FIXME: For SVG Fonts we need to use the attributes defined in the <font-face> if specified. // Compatible with Batik/Opera. if (decoration == UNDERLINE) return fontMetrics.ascent() + thickness * 1.5f; if (decoration == OVERLINE) return thickness; if (decoration == LINE_THROUGH) return fontMetrics.ascent() * 5.0f / 8.0f; ASSERT_NOT_REACHED(); return 0.0f; }
int GlyphCache::get_character_index(FontEngine *font_engine, GraphicContext &gc, const std::string &text, const Point &point) { int dest_x = 0; int dest_y = 0; int character_counter = 0; FontMetrics fm = get_font_metrics(); int font_height = fm.get_height(); int font_ascent = fm.get_ascent(); int font_external_leading = fm.get_external_leading(); std::vector<std::string> lines = StringHelp::split_text(text, "\n", false); for (std::vector<std::string>::size_type i=0; i<lines.size(); i++) { int xpos = dest_x; int ypos = dest_y; std::string &textline = lines[i]; std::string::size_type string_length = textline.length(); // Scan the string UTF8_Reader reader(textline.data(), textline.length()); while(!reader.is_end()) { unsigned int glyph = reader.get_char(); std::string::size_type glyph_pos = reader.get_position(); reader.next(); Font_TextureGlyph *gptr = get_glyph(font_engine, gc, glyph); if (gptr == NULL) continue; Rect position(xpos, ypos - font_ascent, Size(gptr->increment.x, gptr->increment.y + font_height + font_external_leading)); if (position.contains(point)) { return glyph_pos + character_counter; } xpos += gptr->increment.x; ypos += gptr->increment.y; } dest_y += font_height + font_external_leading; character_counter += string_length + 1; // (Including the '\n') } return -1; // Not found }
void Font::draw_text(Canvas &canvas, float dest_x, float dest_y, const std::string &text, const Colorf &color) { if (impl) { FontMetrics fm = get_font_metrics(); int line_spacing = fm.get_height() + fm.get_external_leading(); std::vector<std::string> lines = StringHelp::split_text(text, "\n", false); for (std::vector<std::string>::size_type i=0; i<lines.size(); i++) { impl->draw_text(canvas, dest_x, dest_y, lines[i], color); dest_y += line_spacing; } } }
int FontProvider_Sprite::get_character_index(GraphicContext &gc, const std::string &text, const Point &point) { int dest_x = 0; int dest_y = 0; int character_counter = 0; FontMetrics fm = get_font_metrics(); int font_height = fm.get_height(); int font_external_leading = fm.get_external_leading(); std::vector<std::string> lines = StringHelp::split_text(text, "\n", false); for (std::vector<std::string>::size_type i=0; i<lines.size(); i++) { int xpos = dest_x; int ypos = dest_y; std::string &textline = lines[i]; std::string::size_type string_length = textline.length(); // Scan the string for (std::string::size_type p = 0; p < string_length; p++) { Font_Sprite_Glyph *gptr = get_glyph(textline[p]); int glyph_width; if (gptr) { glyph_width = spr_glyphs.get_frame_size(gptr->sprite_index).width; } else { glyph_width = spacelen; } Rect position(xpos, ypos - font_height, Size(glyph_width, font_height + font_external_leading)); if (position.contains(point)) return ((int) p) + character_counter; xpos += glyph_width; } dest_y += font_height + font_external_leading; character_counter += string_length + 1; // (Including the '\n') } return -1; // Not found }
VerticalTextPosition GUIComponent::get_vertical_text_align(Canvas &canvas, const Rect &content_rect) { Font font = get_font(); // See diagram in: Documentation\Overview\fonts.html (Font Metrics) FontMetrics metrics = font.get_font_metrics(); float align_height = metrics.get_ascent() - metrics.get_internal_leading(); float content_height = content_rect.get_height(); float baseline = (content_height + align_height) / 2.0f; VerticalTextPosition result; result.baseline = baseline + content_rect.top; result.top = result.baseline - metrics.get_ascent(); result.bottom = result.baseline + metrics.get_descent(); return result; }
Font::Font(Canvas &canvas, const std::string &typeface_name, Sprite &sprite, const std::string &glyph_list, float spacelen, bool monospace, const FontMetrics &metrics) { FontDescription desc; desc.set_height(metrics.get_height()); FontFamily font_family(typeface_name); font_family.add(canvas, sprite, glyph_list, spacelen, monospace, metrics); impl = std::make_shared<Font_Impl>(font_family, desc); }
int computeUnderlineOffset(TextUnderlinePosition underlinePosition, const FontMetrics& fontMetrics, const InlineTextBox* inlineTextBox, int textDecorationThickness) { // This represents the gap between the baseline and the closest edge of the underline. int gap = std::max<int>(1, ceilf(textDecorationThickness / 2.0)); // FIXME: The code for visual overflow detection passes in a null inline text box. This means it is now // broken for the case where auto needs to behave like "under". // According to the specification TextUnderlinePositionAuto should avoid drawing through glyphs in // scripts where it would not be appropriate (e.g., ideographs). // Strictly speaking this can occur whenever the line contains ideographs // even if it is horizontal, but detecting this has performance implications. For now we only work with // vertical text, since we already determined the baseline type to be ideographic in that // case. TextUnderlinePosition resolvedUnderlinePosition = underlinePosition == TextUnderlinePositionAuto && inlineTextBox && inlineTextBox->root().baselineType() == IdeographicBaseline ? TextUnderlinePositionUnder : TextUnderlinePositionAlphabetic; switch (resolvedUnderlinePosition) { case TextUnderlinePositionAlphabetic: return fontMetrics.ascent() + gap; case TextUnderlinePositionUnder: { ASSERT(inlineTextBox); // Position underline relative to the bottom edge of the lowest element's content box. const RootInlineBox& rootBox = inlineTextBox->root(); const RenderElement* decorationRenderer = inlineTextBox->parent()->renderer().enclosingRendererWithTextDecoration(TextDecorationUnderline, inlineTextBox->isFirstLine()); float offset; if (inlineTextBox->renderer().style().isFlippedLinesWritingMode()) { offset = inlineTextBox->logicalTop(); rootBox.minLogicalTopForTextDecorationLine(offset, decorationRenderer, TextDecorationUnderline); offset = inlineTextBox->logicalTop() - offset; } else { offset = inlineTextBox->logicalBottom(); rootBox.maxLogicalBottomForTextDecorationLine(offset, decorationRenderer, TextDecorationUnderline); offset -= inlineTextBox->logicalBottom(); } return inlineTextBox->logicalHeight() + gap + std::max<float>(offset, 0); } case TextUnderlinePositionAuto: ASSERT_NOT_REACHED(); } ASSERT_NOT_REACHED(); return fontMetrics.ascent() + gap; }
void TPopupMenu::show(Component* origin, int x, int y) { if (items.size() <= 0) { return; } base = origin; int fw = 100; FontMetrics* fm = getFontMetrics(); int fh = fm->getHeight("0") + 6; int h = 0; for (int ii = 0; ii < items.size(); ii++) { TMenuItem* item = (TMenuItem*)items.get(ii); switch (item->getType()) { case TMenuItem::TYPE_ITEM: if (fm->getWidth(item->getTitle()) + 20 > fw) { fw = fm->getWidth(item->getTitle()) + 20; } break; default: break; } } for (int ii = 0; ii < items.size(); ii++) { TMenuItem* item = (TMenuItem*)items.get(ii); switch (item->getType()) { case TMenuItem::TYPE_ITEM: item->setBounds(base->getX() + x + 2, base->getY() + y + h + 2, fw, fh); h += fh; break; case TMenuItem::TYPE_SEPARATOR: item->setBounds(base->getX() + x + 2, base->getY() + y + h + 2, fw, 8); h += 8; break; } } setBounds(base->getX() + x, base->getY() + y, fw + 4, h + 4); //boo RootWindow* root = (RootWindow*)base->getMainWindow(); if (root) { root->ShowPopupMenu(this); } }
static int computeUnderlineOffset(const TextUnderlinePosition underlinePosition, const FontMetrics& fontMetrics, const InlineTextBox* inlineTextBox, const float textDecorationThickness) { // Compute the gap between the font and the underline. Use at least one // pixel gap, if underline is thick then use a bigger gap. int gap = 0; // Underline position of zero means draw underline on Baseline Position, // in Blink we need at least 1-pixel gap to adding following check. // Positive underline Position means underline should be drawn above baselin e // and negative value means drawing below baseline, negating the value as in Blink // downward Y-increases. if (fontMetrics.underlinePosition()) gap = -fontMetrics.underlinePositio
template<class FontMetrics> void elidedMultiLength_helper() { QString text1 = QLatin1String("Long Text 1\x9cShorter\x9csmall"); QString text1_long = "Long Text 1"; QString text1_short = "Shorter"; QString text1_small = "small"; FontMetrics fm = FontMetrics(QFont()); int width_long = fm.size(0, text1_long).width(); QCOMPARE(fm.elidedText(text1,Qt::ElideRight, 8000), text1_long); QCOMPARE(fm.elidedText(text1,Qt::ElideRight, width_long + 1), text1_long); QCOMPARE(fm.elidedText(text1,Qt::ElideRight, width_long - 1), text1_short); int width_short = fm.size(0, text1_short).width(); QCOMPARE(fm.elidedText(text1,Qt::ElideRight, width_short + 1), text1_short); QCOMPARE(fm.elidedText(text1,Qt::ElideRight, width_short - 1), text1_small); // Not even wide enough for "small" - should use ellipsis QChar ellipsisChar(0x2026); QString text1_el = QString::fromLatin1("s") + ellipsisChar; int width_small = fm.width(text1_el); QCOMPARE(fm.elidedText(text1,Qt::ElideRight, width_small + 1), text1_el); }
std::string Font::get_clipped_text(Canvas &canvas, const Sizef &box_size, const std::string &text, const std::string &ellipsis_text) { std::string out_string; out_string.reserve(text.length()); if (impl) { Pointf pos; FontMetrics fm = get_font_metrics(canvas); float descent = fm.get_descent(); float line_spacing = fm.get_line_height(); std::vector<std::string> lines = StringHelp::split_text(text, "\n", false); for (std::vector<std::string>::size_type i = 0; i < lines.size(); i++) { if (i == 0 || pos.y + descent < box_size.height) { Sizef size = measure_text(canvas, lines[i]).bbox_size; if (pos.x + size.width <= box_size.width) { if (!out_string.empty()) out_string += "\n"; out_string += lines[i]; } else { Sizef ellipsis = measure_text(canvas, ellipsis_text).bbox_size; int seek_start = 0; int seek_end = lines[i].size(); int seek_center = (seek_start + seek_end) / 2; UTF8_Reader utf8_reader(lines[i].data(), lines[i].length()); while (true) { utf8_reader.set_position(seek_center); utf8_reader.move_to_leadbyte(); if (seek_center != utf8_reader.get_position()) utf8_reader.next(); seek_center = utf8_reader.get_position(); if (seek_center == seek_end) break; utf8_reader.set_position(seek_start); utf8_reader.next(); if (utf8_reader.get_position() == seek_end) break; Sizef text_size = measure_text(canvas, lines[i].substr(0, seek_center)).bbox_size; if (pos.x + text_size.width + ellipsis.width >= box_size.width) seek_end = seek_center; else seek_start = seek_center; seek_center = (seek_start + seek_end) / 2; } if (!out_string.empty()) out_string += "\n"; out_string += lines[i].substr(0, seek_center) + ellipsis_text; } pos.y += line_spacing; } } } return out_string; }
float CanvasRenderingContext2D::getFontBaseline( const FontMetrics& fontMetrics) const { // If the font is so tiny that the lroundf operations result in two // different types of text baselines to return the same baseline, use // floating point metrics (crbug.com/338908). // If you changed the heuristic here, for consistency please also change it // in SimpleFontData::platformInit(). bool useFloatAscentDescent = fontMetrics.ascent() < 3 || fontMetrics.height() < 2; switch (state().getTextBaseline()) { case TopTextBaseline: return useFloatAscentDescent ? fontMetrics.floatAscent() : fontMetrics.ascent(); case HangingTextBaseline: // According to // http://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling // "FOP (Formatting Objects Processor) puts the hanging baseline at 80% of // the ascender height" return useFloatAscentDescent ? (fontMetrics.floatAscent() * 4.0) / 5.0 : (fontMetrics.ascent() * 4) / 5; case BottomTextBaseline: case IdeographicTextBaseline: return useFloatAscentDescent ? -fontMetrics.floatDescent() : -fontMetrics.descent(); case MiddleTextBaseline: return useFloatAscentDescent ? -fontMetrics.floatDescent() + fontMetrics.floatHeight() / 2.0 : -fontMetrics.descent() + fontMetrics.height() / 2; case AlphabeticTextBaseline: default: // Do nothing. break; } return 0; }