content/base/src/nsLineBreaker.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "nsLineBreaker.h"
michael@0 7 #include "nsContentUtils.h"
michael@0 8 #include "nsILineBreaker.h"
michael@0 9 #include "gfxFont.h" // for the gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_* values
michael@0 10 #include "nsHyphenationManager.h"
michael@0 11 #include "nsHyphenator.h"
michael@0 12 #include "mozilla/gfx/2D.h"
michael@0 13
michael@0 14 nsLineBreaker::nsLineBreaker()
michael@0 15 : mCurrentWordLanguage(nullptr),
michael@0 16 mCurrentWordContainsMixedLang(false),
michael@0 17 mCurrentWordContainsComplexChar(false),
michael@0 18 mAfterBreakableSpace(false), mBreakHere(false),
michael@0 19 mWordBreak(nsILineBreaker::kWordBreak_Normal)
michael@0 20 {
michael@0 21 }
michael@0 22
michael@0 23 nsLineBreaker::~nsLineBreaker()
michael@0 24 {
michael@0 25 NS_ASSERTION(mCurrentWord.Length() == 0, "Should have Reset() before destruction!");
michael@0 26 }
michael@0 27
michael@0 28 static void
michael@0 29 SetupCapitalization(const char16_t* aWord, uint32_t aLength,
michael@0 30 bool* aCapitalization)
michael@0 31 {
michael@0 32 // Capitalize the first alphanumeric character after a space or start
michael@0 33 // of the word.
michael@0 34 // The only space character a word can contain is NBSP.
michael@0 35 bool capitalizeNextChar = true;
michael@0 36 for (uint32_t i = 0; i < aLength; ++i) {
michael@0 37 uint32_t ch = aWord[i];
michael@0 38 if (capitalizeNextChar) {
michael@0 39 if (NS_IS_HIGH_SURROGATE(ch) && i + 1 < aLength &&
michael@0 40 NS_IS_LOW_SURROGATE(aWord[i + 1])) {
michael@0 41 ch = SURROGATE_TO_UCS4(ch, aWord[i + 1]);
michael@0 42 }
michael@0 43 if (nsContentUtils::IsAlphanumeric(ch)) {
michael@0 44 aCapitalization[i] = true;
michael@0 45 capitalizeNextChar = false;
michael@0 46 }
michael@0 47 if (!IS_IN_BMP(ch)) {
michael@0 48 ++i;
michael@0 49 }
michael@0 50 }
michael@0 51 if (ch == 0xA0 /*NBSP*/) {
michael@0 52 capitalizeNextChar = true;
michael@0 53 }
michael@0 54 }
michael@0 55 }
michael@0 56
michael@0 57 nsresult
michael@0 58 nsLineBreaker::FlushCurrentWord()
michael@0 59 {
michael@0 60 uint32_t length = mCurrentWord.Length();
michael@0 61 nsAutoTArray<uint8_t,4000> breakState;
michael@0 62 if (!breakState.AppendElements(length))
michael@0 63 return NS_ERROR_OUT_OF_MEMORY;
michael@0 64
michael@0 65 nsTArray<bool> capitalizationState;
michael@0 66
michael@0 67 if (!mCurrentWordContainsComplexChar) {
michael@0 68 // For break-strict set everything internal to "break", otherwise
michael@0 69 // to "no break"!
michael@0 70 memset(breakState.Elements(),
michael@0 71 mWordBreak == nsILineBreaker::kWordBreak_BreakAll ?
michael@0 72 gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NORMAL :
michael@0 73 gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE,
michael@0 74 length*sizeof(uint8_t));
michael@0 75 } else {
michael@0 76 nsContentUtils::LineBreaker()->
michael@0 77 GetJISx4051Breaks(mCurrentWord.Elements(), length, mWordBreak,
michael@0 78 breakState.Elements());
michael@0 79 }
michael@0 80
michael@0 81 bool autoHyphenate = mCurrentWordLanguage &&
michael@0 82 !mCurrentWordContainsMixedLang;
michael@0 83 uint32_t i;
michael@0 84 for (i = 0; autoHyphenate && i < mTextItems.Length(); ++i) {
michael@0 85 TextItem* ti = &mTextItems[i];
michael@0 86 if (!(ti->mFlags & BREAK_USE_AUTO_HYPHENATION)) {
michael@0 87 autoHyphenate = false;
michael@0 88 }
michael@0 89 }
michael@0 90 if (autoHyphenate) {
michael@0 91 nsRefPtr<nsHyphenator> hyphenator =
michael@0 92 nsHyphenationManager::Instance()->GetHyphenator(mCurrentWordLanguage);
michael@0 93 if (hyphenator) {
michael@0 94 FindHyphenationPoints(hyphenator,
michael@0 95 mCurrentWord.Elements(),
michael@0 96 mCurrentWord.Elements() + length,
michael@0 97 breakState.Elements());
michael@0 98 }
michael@0 99 }
michael@0 100
michael@0 101 uint32_t offset = 0;
michael@0 102 for (i = 0; i < mTextItems.Length(); ++i) {
michael@0 103 TextItem* ti = &mTextItems[i];
michael@0 104 NS_ASSERTION(ti->mLength > 0, "Zero length word contribution?");
michael@0 105
michael@0 106 if ((ti->mFlags & BREAK_SUPPRESS_INITIAL) && ti->mSinkOffset == 0) {
michael@0 107 breakState[offset] = gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE;
michael@0 108 }
michael@0 109 if (ti->mFlags & BREAK_SUPPRESS_INSIDE) {
michael@0 110 uint32_t exclude = ti->mSinkOffset == 0 ? 1 : 0;
michael@0 111 memset(breakState.Elements() + offset + exclude,
michael@0 112 gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE,
michael@0 113 (ti->mLength - exclude)*sizeof(uint8_t));
michael@0 114 }
michael@0 115
michael@0 116 // Don't set the break state for the first character of the word, because
michael@0 117 // it was already set correctly earlier and we don't know what the true
michael@0 118 // value should be.
michael@0 119 uint32_t skipSet = i == 0 ? 1 : 0;
michael@0 120 if (ti->mSink) {
michael@0 121 ti->mSink->SetBreaks(ti->mSinkOffset + skipSet, ti->mLength - skipSet,
michael@0 122 breakState.Elements() + offset + skipSet);
michael@0 123
michael@0 124 if (ti->mFlags & BREAK_NEED_CAPITALIZATION) {
michael@0 125 if (capitalizationState.Length() == 0) {
michael@0 126 if (!capitalizationState.AppendElements(length))
michael@0 127 return NS_ERROR_OUT_OF_MEMORY;
michael@0 128 memset(capitalizationState.Elements(), false, length*sizeof(bool));
michael@0 129 SetupCapitalization(mCurrentWord.Elements(), length,
michael@0 130 capitalizationState.Elements());
michael@0 131 }
michael@0 132 ti->mSink->SetCapitalization(ti->mSinkOffset, ti->mLength,
michael@0 133 capitalizationState.Elements() + offset);
michael@0 134 }
michael@0 135 }
michael@0 136
michael@0 137 offset += ti->mLength;
michael@0 138 }
michael@0 139
michael@0 140 mCurrentWord.Clear();
michael@0 141 mTextItems.Clear();
michael@0 142 mCurrentWordContainsComplexChar = false;
michael@0 143 mCurrentWordContainsMixedLang = false;
michael@0 144 mCurrentWordLanguage = nullptr;
michael@0 145 return NS_OK;
michael@0 146 }
michael@0 147
michael@0 148 nsresult
michael@0 149 nsLineBreaker::AppendText(nsIAtom* aHyphenationLanguage, const char16_t* aText, uint32_t aLength,
michael@0 150 uint32_t aFlags, nsILineBreakSink* aSink)
michael@0 151 {
michael@0 152 NS_ASSERTION(aLength > 0, "Appending empty text...");
michael@0 153
michael@0 154 uint32_t offset = 0;
michael@0 155
michael@0 156 // Continue the current word
michael@0 157 if (mCurrentWord.Length() > 0) {
michael@0 158 NS_ASSERTION(!mAfterBreakableSpace && !mBreakHere, "These should not be set");
michael@0 159
michael@0 160 while (offset < aLength && !IsSpace(aText[offset])) {
michael@0 161 mCurrentWord.AppendElement(aText[offset]);
michael@0 162 if (!mCurrentWordContainsComplexChar && IsComplexChar(aText[offset])) {
michael@0 163 mCurrentWordContainsComplexChar = true;
michael@0 164 }
michael@0 165 UpdateCurrentWordLanguage(aHyphenationLanguage);
michael@0 166 ++offset;
michael@0 167 }
michael@0 168
michael@0 169 if (offset > 0) {
michael@0 170 mTextItems.AppendElement(TextItem(aSink, 0, offset, aFlags));
michael@0 171 }
michael@0 172
michael@0 173 if (offset == aLength)
michael@0 174 return NS_OK;
michael@0 175
michael@0 176 // We encountered whitespace, so we're done with this word
michael@0 177 nsresult rv = FlushCurrentWord();
michael@0 178 if (NS_FAILED(rv))
michael@0 179 return rv;
michael@0 180 }
michael@0 181
michael@0 182 nsAutoTArray<uint8_t,4000> breakState;
michael@0 183 if (aSink) {
michael@0 184 if (!breakState.AppendElements(aLength))
michael@0 185 return NS_ERROR_OUT_OF_MEMORY;
michael@0 186 }
michael@0 187
michael@0 188 nsTArray<bool> capitalizationState;
michael@0 189 if (aSink && (aFlags & BREAK_NEED_CAPITALIZATION)) {
michael@0 190 if (!capitalizationState.AppendElements(aLength))
michael@0 191 return NS_ERROR_OUT_OF_MEMORY;
michael@0 192 memset(capitalizationState.Elements(), false, aLength*sizeof(bool));
michael@0 193 }
michael@0 194
michael@0 195 uint32_t start = offset;
michael@0 196 bool noBreaksNeeded = !aSink ||
michael@0 197 (aFlags == (BREAK_SUPPRESS_INITIAL | BREAK_SUPPRESS_INSIDE | BREAK_SKIP_SETTING_NO_BREAKS) &&
michael@0 198 !mBreakHere && !mAfterBreakableSpace);
michael@0 199 if (noBreaksNeeded) {
michael@0 200 // Skip to the space before the last word, since either the break data
michael@0 201 // here is not needed, or no breaks are set in the sink and there cannot
michael@0 202 // be any breaks in this chunk; all we need is the context for the next
michael@0 203 // chunk (if any)
michael@0 204 offset = aLength;
michael@0 205 while (offset > start) {
michael@0 206 --offset;
michael@0 207 if (IsSpace(aText[offset]))
michael@0 208 break;
michael@0 209 }
michael@0 210 }
michael@0 211 uint32_t wordStart = offset;
michael@0 212 bool wordHasComplexChar = false;
michael@0 213
michael@0 214 nsRefPtr<nsHyphenator> hyphenator;
michael@0 215 if ((aFlags & BREAK_USE_AUTO_HYPHENATION) &&
michael@0 216 !(aFlags & BREAK_SUPPRESS_INSIDE) &&
michael@0 217 aHyphenationLanguage) {
michael@0 218 hyphenator = nsHyphenationManager::Instance()->GetHyphenator(aHyphenationLanguage);
michael@0 219 }
michael@0 220
michael@0 221 for (;;) {
michael@0 222 char16_t ch = aText[offset];
michael@0 223 bool isSpace = IsSpace(ch);
michael@0 224 bool isBreakableSpace = isSpace && !(aFlags & BREAK_SUPPRESS_INSIDE);
michael@0 225
michael@0 226 if (aSink) {
michael@0 227 breakState[offset] =
michael@0 228 mBreakHere || (mAfterBreakableSpace && !isBreakableSpace) ||
michael@0 229 (mWordBreak == nsILineBreaker::kWordBreak_BreakAll) ?
michael@0 230 gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NORMAL :
michael@0 231 gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE;
michael@0 232 }
michael@0 233 mBreakHere = false;
michael@0 234 mAfterBreakableSpace = isBreakableSpace;
michael@0 235
michael@0 236 if (isSpace) {
michael@0 237 if (offset > wordStart && aSink) {
michael@0 238 if (!(aFlags & BREAK_SUPPRESS_INSIDE)) {
michael@0 239 if (wordHasComplexChar) {
michael@0 240 // Save current start-of-word state because GetJISx4051Breaks will
michael@0 241 // set it to false
michael@0 242 uint8_t currentStart = breakState[wordStart];
michael@0 243 nsContentUtils::LineBreaker()->
michael@0 244 GetJISx4051Breaks(aText + wordStart, offset - wordStart,
michael@0 245 mWordBreak,
michael@0 246 breakState.Elements() + wordStart);
michael@0 247 breakState[wordStart] = currentStart;
michael@0 248 }
michael@0 249 if (hyphenator) {
michael@0 250 FindHyphenationPoints(hyphenator,
michael@0 251 aText + wordStart, aText + offset,
michael@0 252 breakState.Elements() + wordStart);
michael@0 253 }
michael@0 254 }
michael@0 255 if (aFlags & BREAK_NEED_CAPITALIZATION) {
michael@0 256 SetupCapitalization(aText + wordStart, offset - wordStart,
michael@0 257 capitalizationState.Elements() + wordStart);
michael@0 258 }
michael@0 259 }
michael@0 260 wordHasComplexChar = false;
michael@0 261 ++offset;
michael@0 262 if (offset >= aLength)
michael@0 263 break;
michael@0 264 wordStart = offset;
michael@0 265 } else {
michael@0 266 if (!wordHasComplexChar && IsComplexChar(ch)) {
michael@0 267 wordHasComplexChar = true;
michael@0 268 }
michael@0 269 ++offset;
michael@0 270 if (offset >= aLength) {
michael@0 271 // Save this word
michael@0 272 mCurrentWordContainsComplexChar = wordHasComplexChar;
michael@0 273 uint32_t len = offset - wordStart;
michael@0 274 char16_t* elems = mCurrentWord.AppendElements(len);
michael@0 275 if (!elems)
michael@0 276 return NS_ERROR_OUT_OF_MEMORY;
michael@0 277 memcpy(elems, aText + wordStart, sizeof(char16_t)*len);
michael@0 278 mTextItems.AppendElement(TextItem(aSink, wordStart, len, aFlags));
michael@0 279 // Ensure that the break-before for this word is written out
michael@0 280 offset = wordStart + 1;
michael@0 281 UpdateCurrentWordLanguage(aHyphenationLanguage);
michael@0 282 break;
michael@0 283 }
michael@0 284 }
michael@0 285 }
michael@0 286
michael@0 287 if (!noBreaksNeeded) {
michael@0 288 // aSink must not be null
michael@0 289 aSink->SetBreaks(start, offset - start, breakState.Elements() + start);
michael@0 290 if (aFlags & BREAK_NEED_CAPITALIZATION) {
michael@0 291 aSink->SetCapitalization(start, offset - start,
michael@0 292 capitalizationState.Elements() + start);
michael@0 293 }
michael@0 294 }
michael@0 295 return NS_OK;
michael@0 296 }
michael@0 297
michael@0 298 void
michael@0 299 nsLineBreaker::FindHyphenationPoints(nsHyphenator *aHyphenator,
michael@0 300 const char16_t *aTextStart,
michael@0 301 const char16_t *aTextLimit,
michael@0 302 uint8_t *aBreakState)
michael@0 303 {
michael@0 304 nsDependentSubstring string(aTextStart, aTextLimit);
michael@0 305 AutoFallibleTArray<bool,200> hyphens;
michael@0 306 if (NS_SUCCEEDED(aHyphenator->Hyphenate(string, hyphens))) {
michael@0 307 for (uint32_t i = 0; i + 1 < string.Length(); ++i) {
michael@0 308 if (hyphens[i]) {
michael@0 309 aBreakState[i + 1] =
michael@0 310 gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_HYPHEN;
michael@0 311 }
michael@0 312 }
michael@0 313 }
michael@0 314 }
michael@0 315
michael@0 316 nsresult
michael@0 317 nsLineBreaker::AppendText(nsIAtom* aHyphenationLanguage, const uint8_t* aText, uint32_t aLength,
michael@0 318 uint32_t aFlags, nsILineBreakSink* aSink)
michael@0 319 {
michael@0 320 NS_ASSERTION(aLength > 0, "Appending empty text...");
michael@0 321
michael@0 322 if (aFlags & (BREAK_NEED_CAPITALIZATION | BREAK_USE_AUTO_HYPHENATION)) {
michael@0 323 // Defer to the Unicode path if capitalization or hyphenation is required
michael@0 324 nsAutoString str;
michael@0 325 const char* cp = reinterpret_cast<const char*>(aText);
michael@0 326 CopyASCIItoUTF16(nsDependentCSubstring(cp, cp + aLength), str);
michael@0 327 return AppendText(aHyphenationLanguage, str.get(), aLength, aFlags, aSink);
michael@0 328 }
michael@0 329
michael@0 330 uint32_t offset = 0;
michael@0 331
michael@0 332 // Continue the current word
michael@0 333 if (mCurrentWord.Length() > 0) {
michael@0 334 NS_ASSERTION(!mAfterBreakableSpace && !mBreakHere, "These should not be set");
michael@0 335
michael@0 336 while (offset < aLength && !IsSpace(aText[offset])) {
michael@0 337 mCurrentWord.AppendElement(aText[offset]);
michael@0 338 if (!mCurrentWordContainsComplexChar &&
michael@0 339 IsComplexASCIIChar(aText[offset])) {
michael@0 340 mCurrentWordContainsComplexChar = true;
michael@0 341 }
michael@0 342 ++offset;
michael@0 343 }
michael@0 344
michael@0 345 if (offset > 0) {
michael@0 346 mTextItems.AppendElement(TextItem(aSink, 0, offset, aFlags));
michael@0 347 }
michael@0 348
michael@0 349 if (offset == aLength) {
michael@0 350 // We did not encounter whitespace so the word hasn't finished yet.
michael@0 351 return NS_OK;
michael@0 352 }
michael@0 353
michael@0 354 // We encountered whitespace, so we're done with this word
michael@0 355 nsresult rv = FlushCurrentWord();
michael@0 356 if (NS_FAILED(rv))
michael@0 357 return rv;
michael@0 358 }
michael@0 359
michael@0 360 nsAutoTArray<uint8_t,4000> breakState;
michael@0 361 if (aSink) {
michael@0 362 if (!breakState.AppendElements(aLength))
michael@0 363 return NS_ERROR_OUT_OF_MEMORY;
michael@0 364 }
michael@0 365
michael@0 366 uint32_t start = offset;
michael@0 367 bool noBreaksNeeded = !aSink ||
michael@0 368 (aFlags == (BREAK_SUPPRESS_INITIAL | BREAK_SUPPRESS_INSIDE | BREAK_SKIP_SETTING_NO_BREAKS) &&
michael@0 369 !mBreakHere && !mAfterBreakableSpace);
michael@0 370 if (noBreaksNeeded) {
michael@0 371 // Skip to the space before the last word, since either the break data
michael@0 372 // here is not needed, or no breaks are set in the sink and there cannot
michael@0 373 // be any breaks in this chunk; all we need is the context for the next
michael@0 374 // chunk (if any)
michael@0 375 offset = aLength;
michael@0 376 while (offset > start) {
michael@0 377 --offset;
michael@0 378 if (IsSpace(aText[offset]))
michael@0 379 break;
michael@0 380 }
michael@0 381 }
michael@0 382 uint32_t wordStart = offset;
michael@0 383 bool wordHasComplexChar = false;
michael@0 384
michael@0 385 for (;;) {
michael@0 386 uint8_t ch = aText[offset];
michael@0 387 bool isSpace = IsSpace(ch);
michael@0 388 bool isBreakableSpace = isSpace && !(aFlags & BREAK_SUPPRESS_INSIDE);
michael@0 389
michael@0 390 if (aSink) {
michael@0 391 // Consider word-break style. Since the break position of CJK scripts
michael@0 392 // will be set by nsILineBreaker, we don't consider CJK at this point.
michael@0 393 breakState[offset] =
michael@0 394 mBreakHere || (mAfterBreakableSpace && !isBreakableSpace) ||
michael@0 395 (mWordBreak == nsILineBreaker::kWordBreak_BreakAll) ?
michael@0 396 gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NORMAL :
michael@0 397 gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE;
michael@0 398 }
michael@0 399 mBreakHere = false;
michael@0 400 mAfterBreakableSpace = isBreakableSpace;
michael@0 401
michael@0 402 if (isSpace) {
michael@0 403 if (offset > wordStart && wordHasComplexChar) {
michael@0 404 if (aSink && !(aFlags & BREAK_SUPPRESS_INSIDE)) {
michael@0 405 // Save current start-of-word state because GetJISx4051Breaks will
michael@0 406 // set it to false
michael@0 407 uint8_t currentStart = breakState[wordStart];
michael@0 408 nsContentUtils::LineBreaker()->
michael@0 409 GetJISx4051Breaks(aText + wordStart, offset - wordStart,
michael@0 410 mWordBreak,
michael@0 411 breakState.Elements() + wordStart);
michael@0 412 breakState[wordStart] = currentStart;
michael@0 413 }
michael@0 414 wordHasComplexChar = false;
michael@0 415 }
michael@0 416
michael@0 417 ++offset;
michael@0 418 if (offset >= aLength)
michael@0 419 break;
michael@0 420 wordStart = offset;
michael@0 421 } else {
michael@0 422 if (!wordHasComplexChar && IsComplexASCIIChar(ch)) {
michael@0 423 wordHasComplexChar = true;
michael@0 424 }
michael@0 425 ++offset;
michael@0 426 if (offset >= aLength) {
michael@0 427 // Save this word
michael@0 428 mCurrentWordContainsComplexChar = wordHasComplexChar;
michael@0 429 uint32_t len = offset - wordStart;
michael@0 430 char16_t* elems = mCurrentWord.AppendElements(len);
michael@0 431 if (!elems)
michael@0 432 return NS_ERROR_OUT_OF_MEMORY;
michael@0 433 uint32_t i;
michael@0 434 for (i = wordStart; i < offset; ++i) {
michael@0 435 elems[i - wordStart] = aText[i];
michael@0 436 }
michael@0 437 mTextItems.AppendElement(TextItem(aSink, wordStart, len, aFlags));
michael@0 438 // Ensure that the break-before for this word is written out
michael@0 439 offset = wordStart + 1;
michael@0 440 break;
michael@0 441 }
michael@0 442 }
michael@0 443 }
michael@0 444
michael@0 445 if (!noBreaksNeeded) {
michael@0 446 aSink->SetBreaks(start, offset - start, breakState.Elements() + start);
michael@0 447 }
michael@0 448 return NS_OK;
michael@0 449 }
michael@0 450
michael@0 451 void
michael@0 452 nsLineBreaker::UpdateCurrentWordLanguage(nsIAtom *aHyphenationLanguage)
michael@0 453 {
michael@0 454 if (mCurrentWordLanguage && mCurrentWordLanguage != aHyphenationLanguage) {
michael@0 455 mCurrentWordContainsMixedLang = true;
michael@0 456 } else {
michael@0 457 mCurrentWordLanguage = aHyphenationLanguage;
michael@0 458 }
michael@0 459 }
michael@0 460
michael@0 461 nsresult
michael@0 462 nsLineBreaker::AppendInvisibleWhitespace(uint32_t aFlags)
michael@0 463 {
michael@0 464 nsresult rv = FlushCurrentWord();
michael@0 465 if (NS_FAILED(rv))
michael@0 466 return rv;
michael@0 467
michael@0 468 bool isBreakableSpace = !(aFlags & BREAK_SUPPRESS_INSIDE);
michael@0 469 if (mAfterBreakableSpace && !isBreakableSpace) {
michael@0 470 mBreakHere = true;
michael@0 471 }
michael@0 472 mAfterBreakableSpace = isBreakableSpace;
michael@0 473 return NS_OK;
michael@0 474 }
michael@0 475
michael@0 476 nsresult
michael@0 477 nsLineBreaker::Reset(bool* aTrailingBreak)
michael@0 478 {
michael@0 479 nsresult rv = FlushCurrentWord();
michael@0 480 if (NS_FAILED(rv))
michael@0 481 return rv;
michael@0 482
michael@0 483 *aTrailingBreak = mBreakHere || mAfterBreakableSpace;
michael@0 484 mBreakHere = false;
michael@0 485 mAfterBreakableSpace = false;
michael@0 486 return NS_OK;
michael@0 487 }

mercurial