nsresult nsLineBreaker::Reset(bool* aTrailingBreak) { nsresult rv = FlushCurrentWord(); if (NS_FAILED(rv)) return rv; *aTrailingBreak = mBreakHere || mAfterBreakableSpace; mBreakHere = PR_FALSE; mAfterBreakableSpace = PR_FALSE; return NS_OK; }
nsresult nsLineBreaker::AppendInvisibleWhitespace(PRUint32 aFlags) { nsresult rv = FlushCurrentWord(); if (NS_FAILED(rv)) return rv; bool isBreakableSpace = !(aFlags & BREAK_SUPPRESS_INSIDE); if (mAfterBreakableSpace && !isBreakableSpace) { mBreakHere = PR_TRUE; } mAfterBreakableSpace = isBreakableSpace; return NS_OK; }
nsresult nsLineBreaker::AppendText(nsIAtom* aLangGroup, const PRUnichar* aText, PRUint32 aLength, PRUint32 aFlags, nsILineBreakSink* aSink) { NS_ASSERTION(aLength > 0, "Appending empty text..."); PRUint32 offset = 0; // Continue the current word if (mCurrentWord.Length() > 0) { NS_ASSERTION(!mAfterBreakableSpace && !mBreakHere, "These should not be set"); while (offset < aLength && !IsSpace(aText[offset])) { mCurrentWord.AppendElement(aText[offset]); if (!mCurrentWordContainsComplexChar && IsComplexChar(aText[offset])) { mCurrentWordContainsComplexChar = PR_TRUE; } UpdateCurrentWordLangGroup(aLangGroup); ++offset; } if (offset > 0) { mTextItems.AppendElement(TextItem(aSink, 0, offset, aFlags)); } if (offset == aLength) return NS_OK; // We encountered whitespace, so we're done with this word nsresult rv = FlushCurrentWord(); if (NS_FAILED(rv)) return rv; } nsAutoTArray<PRUint8,4000> breakState; if (aSink) { if (!breakState.AppendElements(aLength)) return NS_ERROR_OUT_OF_MEMORY; } nsTArray<bool> capitalizationState; if (aSink && (aFlags & BREAK_NEED_CAPITALIZATION)) { if (!capitalizationState.AppendElements(aLength)) return NS_ERROR_OUT_OF_MEMORY; memset(capitalizationState.Elements(), PR_FALSE, aLength); } PRUint32 start = offset; bool noBreaksNeeded = !aSink || (aFlags == (BREAK_SUPPRESS_INITIAL | BREAK_SUPPRESS_INSIDE | BREAK_SKIP_SETTING_NO_BREAKS) && !mBreakHere && !mAfterBreakableSpace); if (noBreaksNeeded) { // Skip to the space before the last word, since either the break data // here is not needed, or no breaks are set in the sink and there cannot // be any breaks in this chunk; all we need is the context for the next // chunk (if any) offset = aLength; while (offset > start) { --offset; if (IsSpace(aText[offset])) break; } } PRUint32 wordStart = offset; bool wordHasComplexChar = false; nsRefPtr<nsHyphenator> hyphenator; if ((aFlags & BREAK_USE_AUTO_HYPHENATION) && !(aFlags & BREAK_SUPPRESS_INSIDE)) { hyphenator = nsHyphenationManager::Instance()->GetHyphenator(aLangGroup); } for (;;) { PRUnichar ch = aText[offset]; bool isSpace = IsSpace(ch); bool isBreakableSpace = isSpace && !(aFlags & BREAK_SUPPRESS_INSIDE); if (aSink) { breakState[offset] = mBreakHere || (mAfterBreakableSpace && !isBreakableSpace) ? gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NORMAL : gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE; } mBreakHere = PR_FALSE; mAfterBreakableSpace = isBreakableSpace; if (isSpace) { if (offset > wordStart && aSink) { if (!(aFlags & BREAK_SUPPRESS_INSIDE)) { if (wordHasComplexChar) { // Save current start-of-word state because GetJISx4051Breaks will // set it to false PRUint8 currentStart = breakState[wordStart]; nsContentUtils::LineBreaker()-> GetJISx4051Breaks(aText + wordStart, offset - wordStart, breakState.Elements() + wordStart); breakState[wordStart] = currentStart; } if (hyphenator) { FindHyphenationPoints(hyphenator, aText + wordStart, aText + offset, breakState.Elements() + wordStart); } } if (aFlags & BREAK_NEED_CAPITALIZATION) { SetupCapitalization(aText + wordStart, offset - wordStart, capitalizationState.Elements() + wordStart); } } wordHasComplexChar = PR_FALSE; ++offset; if (offset >= aLength) break; wordStart = offset; } else { if (!wordHasComplexChar && IsComplexChar(ch)) { wordHasComplexChar = PR_TRUE; } ++offset; if (offset >= aLength) { // Save this word mCurrentWordContainsComplexChar = wordHasComplexChar; PRUint32 len = offset - wordStart; PRUnichar* elems = mCurrentWord.AppendElements(len); if (!elems) return NS_ERROR_OUT_OF_MEMORY; memcpy(elems, aText + wordStart, sizeof(PRUnichar)*len); mTextItems.AppendElement(TextItem(aSink, wordStart, len, aFlags)); // Ensure that the break-before for this word is written out offset = wordStart + 1; UpdateCurrentWordLangGroup(aLangGroup); break; } } } if (!noBreaksNeeded) { // aSink must not be null aSink->SetBreaks(start, offset - start, breakState.Elements() + start); if (aFlags & BREAK_NEED_CAPITALIZATION) { aSink->SetCapitalization(start, offset - start, capitalizationState.Elements() + start); } } return NS_OK; }
nsresult nsLineBreaker::AppendText(nsIAtom* aLangGroup, const PRUint8* aText, PRUint32 aLength, PRUint32 aFlags, nsILineBreakSink* aSink) { NS_ASSERTION(aLength > 0, "Appending empty text..."); if (aFlags & (BREAK_NEED_CAPITALIZATION | BREAK_USE_AUTO_HYPHENATION)) { // Defer to the Unicode path if capitalization or hyphenation is required nsAutoString str; const char* cp = reinterpret_cast<const char*>(aText); CopyASCIItoUTF16(nsDependentCSubstring(cp, cp + aLength), str); return AppendText(aLangGroup, str.get(), aLength, aFlags, aSink); } PRUint32 offset = 0; // Continue the current word if (mCurrentWord.Length() > 0) { NS_ASSERTION(!mAfterBreakableSpace && !mBreakHere, "These should not be set"); while (offset < aLength && !IsSpace(aText[offset])) { mCurrentWord.AppendElement(aText[offset]); if (!mCurrentWordContainsComplexChar && IsComplexASCIIChar(aText[offset])) { mCurrentWordContainsComplexChar = PR_TRUE; } ++offset; } if (offset > 0) { mTextItems.AppendElement(TextItem(aSink, 0, offset, aFlags)); } if (offset == aLength) { // We did not encounter whitespace so the word hasn't finished yet. return NS_OK; } // We encountered whitespace, so we're done with this word nsresult rv = FlushCurrentWord(); if (NS_FAILED(rv)) return rv; } nsAutoTArray<PRUint8,4000> breakState; if (aSink) { if (!breakState.AppendElements(aLength)) return NS_ERROR_OUT_OF_MEMORY; } PRUint32 start = offset; bool noBreaksNeeded = !aSink || (aFlags == (BREAK_SUPPRESS_INITIAL | BREAK_SUPPRESS_INSIDE | BREAK_SKIP_SETTING_NO_BREAKS) && !mBreakHere && !mAfterBreakableSpace); if (noBreaksNeeded) { // Skip to the space before the last word, since either the break data // here is not needed, or no breaks are set in the sink and there cannot // be any breaks in this chunk; all we need is the context for the next // chunk (if any) offset = aLength; while (offset > start) { --offset; if (IsSpace(aText[offset])) break; } } PRUint32 wordStart = offset; bool wordHasComplexChar = false; for (;;) { PRUint8 ch = aText[offset]; bool isSpace = IsSpace(ch); bool isBreakableSpace = isSpace && !(aFlags & BREAK_SUPPRESS_INSIDE); if (aSink) { breakState[offset] = mBreakHere || (mAfterBreakableSpace && !isBreakableSpace) ? gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NORMAL : gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE; } mBreakHere = PR_FALSE; mAfterBreakableSpace = isBreakableSpace; if (isSpace) { if (offset > wordStart && wordHasComplexChar) { if (aSink && !(aFlags & BREAK_SUPPRESS_INSIDE)) { // Save current start-of-word state because GetJISx4051Breaks will // set it to false PRUint8 currentStart = breakState[wordStart]; nsContentUtils::LineBreaker()-> GetJISx4051Breaks(aText + wordStart, offset - wordStart, breakState.Elements() + wordStart); breakState[wordStart] = currentStart; } wordHasComplexChar = PR_FALSE; } ++offset; if (offset >= aLength) break; wordStart = offset; } else { if (!wordHasComplexChar && IsComplexASCIIChar(ch)) { wordHasComplexChar = PR_TRUE; } ++offset; if (offset >= aLength) { // Save this word mCurrentWordContainsComplexChar = wordHasComplexChar; PRUint32 len = offset - wordStart; PRUnichar* elems = mCurrentWord.AppendElements(len); if (!elems) return NS_ERROR_OUT_OF_MEMORY; PRUint32 i; for (i = wordStart; i < offset; ++i) { elems[i - wordStart] = aText[i]; } mTextItems.AppendElement(TextItem(aSink, wordStart, len, aFlags)); // Ensure that the break-before for this word is written out offset = wordStart + 1; break; } } } if (!noBreaksNeeded) { aSink->SetBreaks(start, offset - start, breakState.Elements() + start); } return NS_OK; }
nsresult nsLineBreaker::AppendText(nsIAtom* aHyphenationLanguage, const char16_t* aText, uint32_t aLength, uint32_t aFlags, nsILineBreakSink* aSink) { NS_ASSERTION(aLength > 0, "Appending empty text..."); uint32_t offset = 0; // Continue the current word if (mCurrentWord.Length() > 0) { NS_ASSERTION(!mAfterBreakableSpace && !mBreakHere, "These should not be set"); while (offset < aLength && !IsSpace(aText[offset])) { mCurrentWord.AppendElement(aText[offset]); if (!mCurrentWordContainsComplexChar && IsComplexChar(aText[offset])) { mCurrentWordContainsComplexChar = true; } UpdateCurrentWordLanguage(aHyphenationLanguage); ++offset; } if (offset > 0) { mTextItems.AppendElement(TextItem(aSink, 0, offset, aFlags)); } if (offset == aLength) return NS_OK; // We encountered whitespace, so we're done with this word nsresult rv = FlushCurrentWord(); if (NS_FAILED(rv)) return rv; } AutoTArray<uint8_t,4000> breakState; if (aSink) { if (!breakState.AppendElements(aLength)) return NS_ERROR_OUT_OF_MEMORY; } bool noCapitalizationNeeded = true; nsTArray<bool> capitalizationState; if (aSink && (aFlags & BREAK_NEED_CAPITALIZATION)) { if (!capitalizationState.AppendElements(aLength)) return NS_ERROR_OUT_OF_MEMORY; memset(capitalizationState.Elements(), false, aLength*sizeof(bool)); noCapitalizationNeeded = false; } uint32_t start = offset; bool noBreaksNeeded = !aSink || ((aFlags & NO_BREAKS_NEEDED_FLAGS) == NO_BREAKS_NEEDED_FLAGS && !mBreakHere && !mAfterBreakableSpace); if (noBreaksNeeded && noCapitalizationNeeded) { // Skip to the space before the last word, since either the break data // here is not needed, or no breaks are set in the sink and there cannot // be any breaks in this chunk; and we don't need to do word-initial // capitalization. All we need is the context for the next chunk (if any). offset = aLength; while (offset > start) { --offset; if (IsSpace(aText[offset])) break; } } uint32_t wordStart = offset; bool wordHasComplexChar = false; RefPtr<nsHyphenator> hyphenator; if ((aFlags & BREAK_USE_AUTO_HYPHENATION) && !(aFlags & BREAK_SUPPRESS_INSIDE) && aHyphenationLanguage) { hyphenator = nsHyphenationManager::Instance()->GetHyphenator(aHyphenationLanguage); } for (;;) { char16_t ch = aText[offset]; bool isSpace = IsSpace(ch); bool isBreakableSpace = isSpace && !(aFlags & BREAK_SUPPRESS_INSIDE); if (aSink && !noBreaksNeeded) { breakState[offset] = mBreakHere || (mAfterBreakableSpace && !isBreakableSpace) || (mWordBreak == nsILineBreaker::kWordBreak_BreakAll) ? gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NORMAL : gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE; } mBreakHere = false; mAfterBreakableSpace = isBreakableSpace; if (isSpace) { if (offset > wordStart && aSink) { if (!(aFlags & BREAK_SUPPRESS_INSIDE)) { if (wordHasComplexChar) { // Save current start-of-word state because GetJISx4051Breaks will // set it to false uint8_t currentStart = breakState[wordStart]; nsContentUtils::LineBreaker()-> GetJISx4051Breaks(aText + wordStart, offset - wordStart, mWordBreak, breakState.Elements() + wordStart); breakState[wordStart] = currentStart; } if (hyphenator) { FindHyphenationPoints(hyphenator, aText + wordStart, aText + offset, breakState.Elements() + wordStart); } } if (!noCapitalizationNeeded) { SetupCapitalization(aText + wordStart, offset - wordStart, capitalizationState.Elements() + wordStart); } } wordHasComplexChar = false; ++offset; if (offset >= aLength) break; wordStart = offset; } else { if (!wordHasComplexChar && IsComplexChar(ch)) { wordHasComplexChar = true; } ++offset; if (offset >= aLength) { // Save this word mCurrentWordContainsComplexChar = wordHasComplexChar; uint32_t len = offset - wordStart; char16_t* elems = mCurrentWord.AppendElements(len); if (!elems) return NS_ERROR_OUT_OF_MEMORY; memcpy(elems, aText + wordStart, sizeof(char16_t)*len); mTextItems.AppendElement(TextItem(aSink, wordStart, len, aFlags)); // Ensure that the break-before for this word is written out offset = wordStart + 1; UpdateCurrentWordLanguage(aHyphenationLanguage); break; } } } if (aSink) { if (!noBreaksNeeded) { aSink->SetBreaks(start, offset - start, breakState.Elements() + start); } if (!noCapitalizationNeeded) { aSink->SetCapitalization(start, offset - start, capitalizationState.Elements() + start); } } return NS_OK; }