unsigned Character::expansionOpportunityCount(const LChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion, const TextJustify textJustify) { unsigned count = 0; if (textJustify == TextJustifyDistribute) { isAfterExpansion = true; return length; } if (direction == LTR) { for (size_t i = 0; i < length; ++i) { if (treatAsSpace(characters[i])) { count++; isAfterExpansion = true; } else { isAfterExpansion = false; } } } else { for (size_t i = length; i > 0; --i) { if (treatAsSpace(characters[i - 1])) { count++; isAfterExpansion = true; } else { isAfterExpansion = false; } } } return count; }
unsigned Font::expansionOpportunityCount(const UChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion) { static bool expandAroundIdeographs = canExpandAroundIdeographsInComplexText(); unsigned count = 0; if (direction == LTR) { for (size_t i = 0; i < length; ++i) { UChar32 character = characters[i]; if (treatAsSpace(character)) { count++; isAfterExpansion = true; continue; } if (U16_IS_LEAD(character) && i + 1 < length && U16_IS_TRAIL(characters[i + 1])) { character = U16_GET_SUPPLEMENTARY(character, characters[i + 1]); i++; } if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) { if (!isAfterExpansion) count++; count++; isAfterExpansion = true; continue; } isAfterExpansion = false; } } else { for (size_t i = length; i > 0; --i) { UChar32 character = characters[i - 1]; if (treatAsSpace(character)) { count++; isAfterExpansion = true; continue; } if (U16_IS_TRAIL(character) && i > 1 && U16_IS_LEAD(characters[i - 2])) { character = U16_GET_SUPPLEMENTARY(characters[i - 2], character); i--; } if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) { if (!isAfterExpansion) count++; count++; isAfterExpansion = true; continue; } isAfterExpansion = false; } } return count; }
unsigned Character::expansionOpportunityCount(const UChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion, const TextJustify textJustify) { unsigned count = 0; if (direction == LTR) { for (size_t i = 0; i < length; ++i) { UChar32 character = characters[i]; if (treatAsSpace(character)) { count++; isAfterExpansion = true; continue; } if (U16_IS_LEAD(character) && i + 1 < length && U16_IS_TRAIL(characters[i + 1])) { character = U16_GET_SUPPLEMENTARY(character, characters[i + 1]); i++; } if (textJustify == TextJustify::TextJustifyAuto && isCJKIdeographOrSymbol(character)) { if (!isAfterExpansion) count++; count++; isAfterExpansion = true; continue; } isAfterExpansion = false; } } else { for (size_t i = length; i > 0; --i) { UChar32 character = characters[i - 1]; if (treatAsSpace(character)) { count++; isAfterExpansion = true; continue; } if (U16_IS_TRAIL(character) && i > 1 && U16_IS_LEAD(characters[i - 2])) { character = U16_GET_SUPPLEMENTARY(characters[i - 2], character); i--; } if (textJustify == TextJustify::TextJustifyAuto && isCJKIdeographOrSymbol(character)) { if (!isAfterExpansion) count++; count++; isAfterExpansion = true; continue; } isAfterExpansion = false; } } return count; }
void UniscribeHelper::adjustSpaceAdvances() { if (m_spaceWidth == 0) return; int spaceWidthWithoutLetterSpacing = m_spaceWidth - m_letterSpacing; // This mostly matches what WebKit's UniscribeController::shapeAndPlaceItem. for (size_t run = 0; run < m_runs.size(); run++) { Shaping& shaping = m_shapes[run]; for (int i = 0; i < shaping.charLength(); i++) { if (!treatAsSpace(m_input[m_runs[run].iCharPos + i])) continue; int glyphIndex = shaping.m_logs[i]; int currentAdvance = shaping.m_advance[glyphIndex]; // currentAdvance does not include additional letter-spacing, but // space_width does. Here we find out how off we are from the // correct width for the space not including letter-spacing, then // just subtract that diff. int diff = currentAdvance - spaceWidthWithoutLetterSpacing; // The shaping can consist of a run of text, so only subtract the // difference in the width of the glyph. shaping.m_advance[glyphIndex] -= diff; shaping.m_abc.abcB -= diff; } } }
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*, GlyphOverflow*) const { if (!run.length()) return 0; if (run.length() == 1 && treatAsSpace(run[0])) return QFontMetrics(font()).width(space) + run.padding(); String sanitized = Font::normalizeSpaces(String(run.characters(), run.length())); QString string = fromRawDataWithoutRef(sanitized); int w = QFontMetrics(font()).width(string); // WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does) if (treatAsSpace(run[0])) w -= m_wordSpacing; return w + run.padding(); }
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*) const { if (!run.length()) return 0; const QString string = fixSpacing(qstring(run)); int w = QFontMetrics(font()).width(string); // WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does) if (treatAsSpace(run[0])) w -= m_wordSpacing; return w + run.padding(); }
unsigned Font::expansionOpportunityCount(const LChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion) { unsigned count = 0; if (direction == LTR) { for (size_t i = 0; i < length; ++i) { if (treatAsSpace(characters[i])) { count++; isAfterExpansion = true; } else isAfterExpansion = false; } } else { for (size_t i = length; i > 0; --i) { if (treatAsSpace(characters[i - 1])) { count++; isAfterExpansion = true; } else isAfterExpansion = false; } } return count; }
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*) const { if (!run.length()) return 0; const QString string = fixSpacing(qstring(run)); QTextLayout layout(string, font()); QTextLine line = setupLayout(&layout, run); int w = int(line.naturalTextWidth()); // WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does) if (treatAsSpace(run[0])) w -= m_wordSpacing; return w + run.padding(); }
float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { if (!primaryFont()->platformData().size()) return 0; if (!run.length()) return 0; String sanitized = Font::normalizeSpaces(run.characters(), run.length()); QString string = fromRawDataWithoutRef(sanitized); int w = QFontMetrics(font()).width(string, -1, Qt::TextBypassShaping); // WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does) if (treatAsSpace(run[0])) w -= m_wordSpacing; return w + run.expansion(); }
float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) if (!run.length()) return 0; String sanitized = Font::normalizeSpaces(String(run.characters(), run.length())); QString string = fromRawDataWithoutRef(sanitized); int w = QFontMetrics(font()).width(string, -1, Qt::TextBypassShaping); // WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does) if (treatAsSpace(run[0])) w -= m_wordSpacing; return w + run.padding(); #else Q_ASSERT(false); return 0.0f; #endif }
void UniscribeHelper::applySpacing() { for (size_t run = 0; run < m_runs.size(); run++) { Shaping& shaping = m_shapes[run]; bool isRtl = m_runs[run].a.fRTL; if (m_letterSpacing != 0) { // RTL text gets padded to the left of each character. We increment // the run's advance to make this happen. This will be balanced out // by NOT adding additional advance to the last glyph in the run. if (isRtl) shaping.m_prePadding += m_letterSpacing; // Go through all the glyphs in this run and increase the "advance" // to account for letter spacing. We adjust letter spacing only on // cluster boundaries. // // This works for most scripts, but may have problems with some // indic scripts. This behavior is better than Firefox or IE for // Hebrew. for (int i = 0; i < shaping.glyphLength(); i++) { if (shaping.m_visualAttributes[i].fClusterStart) { // Ick, we need to assign the extra space so that the glyph // comes first, then is followed by the space. This is // opposite for RTL. if (isRtl) { if (i != shaping.glyphLength() - 1) { // All but the last character just get the spacing // applied to their advance. The last character // doesn't get anything, shaping.m_advance[i] += m_letterSpacing; shaping.m_abc.abcB += m_letterSpacing; } } else { // LTR case is easier, we just add to the advance. shaping.m_advance[i] += m_letterSpacing; shaping.m_abc.abcB += m_letterSpacing; } } } } // Go through all the characters to find whitespace and insert the // extra wordspacing amount for the glyphs they correspond to. if (m_wordSpacing != 0) { for (int i = 0; i < shaping.charLength(); i++) { if (!treatAsSpace(m_input[m_runs[run].iCharPos + i])) continue; // The char in question is a word separator... int glyphIndex = shaping.m_logs[i]; // Spaces will not have a glyph in Uniscribe, it will just add // additional advance to the character to the left of the // space. The space's corresponding glyph will be the character // following it in reading order. if (isRtl) { // In RTL, the glyph to the left of the space is the same // as the first glyph of the following character, so we can // just increment it. shaping.m_advance[glyphIndex] += m_wordSpacing; shaping.m_abc.abcB += m_wordSpacing; } else { // LTR is actually more complex here, we apply it to the // previous character if there is one, otherwise we have to // apply it to the leading space of the run. if (glyphIndex == 0) shaping.m_prePadding += m_wordSpacing; else { shaping.m_advance[glyphIndex - 1] += m_wordSpacing; shaping.m_abc.abcB += m_wordSpacing; } } } } // m_wordSpacing != 0 // Loop for next run... } }