void computeNormalizedSpaces(const TextRun& run, bool mirror, String& normalizedSpacesStringCache) { if (normalizedSpacesStringCache.length() == static_cast<unsigned>(run.charactersLength())) return; if (run.is8Bit()) normalizedSpacesStringCache = Font::normalizeSpaces(run.characters8(), run.charactersLength()); else normalizedSpacesStringCache = Font::normalizeSpaces(run.characters16(), run.charactersLength()); if (mirror) normalizedSpacesStringCache = createStringWithMirroredCharacters(normalizedSpacesStringCache); }
void LayoutSVGInlineText::updateMetricsList(bool& lastCharacterWasWhiteSpace) { m_metrics.clear(); if (!textLength()) return; TextRun run = constructTextRun(*this, 0, textLength(), styleRef().direction()); BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver; BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs(); bool bidiOverride = isOverride(styleRef().unicodeBidi()); BidiStatus status(LTR, bidiOverride); if (run.is8Bit() || bidiOverride) { WTF::Unicode::CharDirection direction = WTF::Unicode::LeftToRight; // If BiDi override is in effect, use the specified direction. if (bidiOverride && !styleRef().isLeftToRightDirection()) direction = WTF::Unicode::RightToLeft; bidiRuns.addRun(new BidiCharacterRun(0, run.charactersLength(), status.context.get(), direction)); } else { status.last = status.lastStrong = WTF::Unicode::OtherNeutral; bidiResolver.setStatus(status); bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&run, 0)); const bool hardLineBreak = false; const bool reorderRuns = false; bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length()), NoVisualOverride, hardLineBreak, reorderRuns); } for (const BidiCharacterRun* bidiRun = bidiRuns.firstRun(); bidiRun; bidiRun = bidiRun->next()) { TextRun subRun = constructTextRun(*this, bidiRun->start(), bidiRun->stop() - bidiRun->start(), bidiRun->direction()); addMetricsFromRun(subRun, lastCharacterWasWhiteSpace); } bidiResolver.runs().deleteRuns(); }
static float textWidth(const RenderText& text, unsigned from, unsigned length, float xPosition, const RenderStyle& style) { if (style.font().isFixedPitch() || (!from && length == text.textLength())) return text.width(from, length, style.font(), xPosition, nullptr, nullptr); // FIXME: Add templated UChar/LChar paths. TextRun run = text.is8Bit() ? TextRun(text.characters8() + from, length) : TextRun(text.characters16() + from, length); run.setCharactersLength(text.textLength() - from); ASSERT(run.charactersLength() >= run.length()); run.setXPos(xPosition); return style.font().width(run); }
float ShapeResult::fillGlyphBufferForTextEmphasisRun(GlyphBuffer* glyphBuffer, const RunInfo* run, const TextRun& textRun, const GlyphData* emphasisData, float initialAdvance, unsigned from, unsigned to, unsigned runOffset) { if (!run) return 0; unsigned graphemesInCluster = 1; float clusterAdvance = 0; FloatPoint glyphCenter = emphasisData->fontData-> boundsForGlyph(emphasisData->glyph).center(); TextDirection direction = textRun.direction(); // A "cluster" in this context means a cluster as it is used by HarfBuzz: // The minimal group of characters and corresponding glyphs, that cannot be broken // down further from a text shaping point of view. // A cluster can contain multiple glyphs and grapheme clusters, with mutually // overlapping boundaries. Below we count grapheme clusters per HarfBuzz clusters, // then linearly split the sum of corresponding glyph advances by the number of // grapheme clusters in order to find positions for emphasis mark drawing. uint16_t clusterStart = direction == RTL ? run->m_startIndex + run->m_numCharacters + runOffset : run->glyphToCharacterIndex(0) + runOffset; float advanceSoFar = initialAdvance; unsigned numGlyphs = run->m_numGlyphs; for (unsigned i = 0; i < numGlyphs; ++i) { const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i]; uint16_t currentCharacterIndex = run->m_startIndex + glyphData.characterIndex + runOffset; bool isRunEnd = (i + 1 == numGlyphs); bool isClusterEnd = isRunEnd || (run->glyphToCharacterIndex(i + 1) + runOffset != currentCharacterIndex); if ((direction == RTL && currentCharacterIndex >= to) || (direction != RTL && currentCharacterIndex < from)) { advanceSoFar += glyphData.advance; direction == RTL ? --clusterStart : ++clusterStart; continue; } clusterAdvance += glyphData.advance; if (textRun.is8Bit()) { float glyphAdvanceX = glyphData.advance; if (Character::canReceiveTextEmphasis(textRun[currentCharacterIndex])) { addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, advanceSoFar + glyphAdvanceX / 2); } advanceSoFar += glyphAdvanceX; } else if (isClusterEnd) { uint16_t clusterEnd; if (direction == RTL) clusterEnd = currentCharacterIndex; else clusterEnd = isRunEnd ? run->m_startIndex + run->m_numCharacters + runOffset : run->glyphToCharacterIndex(i + 1) + runOffset; graphemesInCluster = countGraphemesInCluster(textRun.characters16(), textRun.charactersLength(), clusterStart, clusterEnd); if (!graphemesInCluster || !clusterAdvance) continue; float glyphAdvanceX = clusterAdvance / graphemesInCluster; for (unsigned j = 0; j < graphemesInCluster; ++j) { // Do not put emphasis marks on space, separator, and control characters. if (Character::canReceiveTextEmphasis(textRun[currentCharacterIndex])) addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, advanceSoFar + glyphAdvanceX / 2); advanceSoFar += glyphAdvanceX; } clusterStart = clusterEnd; clusterAdvance = 0; } } return advanceSoFar - initialAdvance; }