bool TextStyleBuilder::prepareLabel(TextStyle::Parameters& _params, Label::Type _type) { if (_params.text.empty() || _params.fontSize <= 0.f) { LOGD("invalid params: '%s' %f", _params.text.c_str(), _params.fontSize); return false; } // Apply text transforms const std::string* renderText; std::string text; if (_params.transform == TextLabelProperty::Transform::none) { renderText = &_params.text; } else { text = applyTextTransform(_params, _params.text); renderText = &text; } // Scale factor by which the texture glyphs are scaled to match fontSize _params.fontScale = _params.fontSize / _params.font->size(); // Stroke width is normalized by the distance of the SDF spread, then // scaled to 255 and packed into the "alpha" channel of stroke. // Maximal strokeWidth is 3px, attribute is normalized to 0-1 range. auto ctx = m_style.context(); uint32_t strokeAttrib = std::max(_params.strokeWidth / ctx->maxStrokeWidth() * 255.f, 0.f); if (strokeAttrib > 255) { LOGN("stroke_width too large: %f / %f", _params.strokeWidth, strokeAttrib/255.f); strokeAttrib = 255; } m_attributes.stroke = (_params.strokeColor & 0x00ffffff) + (strokeAttrib << 24); m_attributes.fill = _params.fill; m_attributes.fontScale = _params.fontScale * 64.f; if (m_attributes.fontScale > 255) { LOGN("Too large font scale %f, maximal scale is 4", _params.fontScale); m_attributes.fontScale = 255; } m_attributes.quadsStart = m_quads.size(); m_attributes.textRanges = TextRange{}; glm::vec2 bbox(0); if (ctx->layoutText(_params, *renderText, m_quads, m_atlasRefs, bbox, m_attributes.textRanges)) { m_attributes.width = bbox.x; m_attributes.height = bbox.y; return true; } return false; }
void LayoutMenuList::updateOptionsWidth() const { float maxOptionWidth = 0; for (const auto& option : selectElement()->optionList()) { String text = option->textIndentedToRespectGroupLabel(); const ComputedStyle* itemStyle = option->computedStyle() ? option->computedStyle() : style(); applyTextTransform(itemStyle, text, ' '); // We apply SELECT's style, not OPTION's style because m_optionsWidth is // used to determine intrinsic width of the menulist box. TextRun textRun = constructTextRun(style()->font(), text, *style()); maxOptionWidth = std::max(maxOptionWidth, style()->font().width(textRun)); } m_optionsWidth = static_cast<int>(ceilf(maxOptionWidth)); }
bool TextBuffer::addLabel(const TextStyle::Parameters& _params, Label::Transform _transform, Label::Type _type, FontContext& _fontContext) { if (_params.fontId < 0 || _params.fontSize <= 0.f || _params.text.size() == 0) { return false; } /// Apply text transforms const std::string* renderText; std::string text; if (_params.transform == TextLabelProperty::Transform::none) { renderText = &_params.text; } else { text = applyTextTransform(_params, _params.text); renderText = &text; } if (!_fontContext.lock()) { return false; } /// Rasterize the glyphs auto& quads = _fontContext.rasterize(*renderText, _params.fontId, _params.fontSize, _params.blurSpread); size_t numGlyphs = quads.size(); if (numGlyphs == 0) { _fontContext.unlock(); return false; } auto& vertices = m_vertices[0]; int vertexOffset = vertices.size(); int numVertices = numGlyphs * 4; // Stroke width is normalized by the distance of the SDF spread, then scaled // to a char, then packed into the "alpha" channel of stroke. The .25 scaling // probably has to do with how the SDF is generated, but honestly I'm not sure // what it represents. uint32_t strokeWidth = _params.strokeWidth / _params.blurSpread * 255. * .25; uint32_t stroke = (_params.strokeColor & 0x00ffffff) + (strokeWidth << 24); FontContext::FontMetrics metrics = _fontContext.getMetrics(); /// Apply word wrapping glm::vec2 bbox; std::vector<TextBuffer::WordBreak> wordBreaks; int nLine = applyWordWrapping(quads, _params, _fontContext.getMetrics(), _type, &bbox, wordBreaks); /// Generate the quads for (int i = 0; i < int(quads.size()); ++i) { if (wordBreaks.size() > 0) { bool skip = false; // Skip spaces/CR quads for (int j = 0; j < int(wordBreaks.size()) - 1; ++j) { const auto& b1 = wordBreaks[j]; const auto& b2 = wordBreaks[j + 1]; if (i >= b1.end + 1 && i <= b2.start - 1) { numVertices -= 4; skip = true; break; } } if (skip) { continue; } } const auto& q = quads[i]; vertices.push_back({{q.x0, q.y0}, {q.s0, q.t0}, {-1.f, -1.f, 0.f}, _params.fill, stroke}); vertices.push_back({{q.x0, q.y1}, {q.s0, q.t1}, {-1.f, 1.f, 0.f}, _params.fill, stroke}); vertices.push_back({{q.x1, q.y0}, {q.s1, q.t0}, { 1.f, -1.f, 0.f}, _params.fill, stroke}); vertices.push_back({{q.x1, q.y1}, {q.s1, q.t1}, { 1.f, 1.f, 0.f}, _params.fill, stroke}); } _fontContext.unlock(); m_labels.emplace_back(new TextLabel(_transform, _type, bbox, *this, { vertexOffset, numVertices }, _params.labelOptions, metrics, nLine, _params.anchor)); // TODO: change this in TypeMesh::adVertices() m_nVertices = vertices.size(); return true; }
bool TextBuffer::Builder::prepareLabel(FontContext& _fontContext, const TextStyle::Parameters& _params) { if (_params.fontId < 0 || _params.fontSize <= 0.f || _params.text.size() == 0) { return false; } /// Apply text transforms const std::string* renderText; std::string text; if (_params.transform == TextLabelProperty::Transform::none) { renderText = &_params.text; } else { text = applyTextTransform(_params, _params.text); renderText = &text; } if (!_fontContext.lock()) { return false; } /// Rasterize the glyphs auto& quads = _fontContext.rasterize(*renderText, _params.fontId, _params.fontSize, _params.blurSpread); size_t numGlyphs = quads.size(); if (numGlyphs == 0) { _fontContext.unlock(); return false; } // Stroke width is normalized by the distance of the SDF spread, then scaled // to a char, then packed into the "alpha" channel of stroke. The .25 scaling // probably has to do with how the SDF is generated, but honestly I'm not sure // what it represents. uint32_t strokeWidth = _params.strokeWidth / _params.blurSpread * 255. * .25; uint32_t stroke = (_params.strokeColor & 0x00ffffff) + (strokeWidth << 24); m_metrics = _fontContext.getMetrics(); m_bbox = glm::vec2(0); /// Apply word wrapping int nLine = 1; m_wordBreaks.clear(); nLine = applyWordWrapping(quads, _params, m_metrics); /// Generate the quads float yMin = std::numeric_limits<float>::max(); float xMin = std::numeric_limits<float>::max(); m_scratchVertices.clear(); for (int i = 0; i < int(quads.size()); ++i) { if (m_wordBreaks.size() > 0) { bool skip = false; // Skip spaces/CR quads for (int j = 0; j < int(m_wordBreaks.size()) - 1; ++j) { const auto& b1 = m_wordBreaks[j]; const auto& b2 = m_wordBreaks[j + 1]; if (i >= b1.end + 1 && i <= b2.start - 1) { skip = true; break; } } if (skip) { continue; } } const auto& q = quads[i]; m_scratchVertices.push_back({{q.x0, q.y0}, {q.s0, q.t0}, _params.fill, stroke}); m_scratchVertices.push_back({{q.x0, q.y1}, {q.s0, q.t1}, _params.fill, stroke}); m_scratchVertices.push_back({{q.x1, q.y0}, {q.s1, q.t0}, _params.fill, stroke}); m_scratchVertices.push_back({{q.x1, q.y1}, {q.s1, q.t1}, _params.fill, stroke}); yMin = std::min(yMin, q.y0); xMin = std::min(xMin, q.x0); m_bbox.x = std::max(m_bbox.x, q.x1); m_bbox.y = std::max(m_bbox.y, std::abs(yMin - q.y1)); } m_bbox.x -= xMin; m_quadsLocalOrigin = { xMin, quads[0].y0 }; m_numLines = nLine; _fontContext.unlock(); return true; }