mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
8a0a002cf2
- Bug 1148708: Add missing 'override' annotations in DocAccessibleChild.h. rs=ehsan (d606358545)
- Bug 1210408 - make nsMaiInterfaceAction work with proxies, r=tbsaunde (f7c819c6ae)
- Bug 1210407 - teach nsMaiInterfaceTable to use proxies, r=tbsaunde (4ca4f10b5f)
- bug 1185157 make sure we don't send an event to a destroyed ipc document r=billm (23acf53f75)
- bug 1214864 - make SetCarretOffset() async r=davidb (e3079e9b2d)
- missing of Bug 1139972 - IPC Proxy for charAt, r=tbsaunde (e9593ed752)
- bug 1191598 - Pass MOZ_CURRENT_PROJECT in environment when running post-build automation steps for universal mac builds. r=gps (fc342c6ced)
- Bug 1164596 - Add mach android-emulator command; r=ahal (afeb9b27d1)
- Bug 1223149 - Add basic usage documentation for mach build; r=glandium (bfb802d175)
- Bug 1182301 - Improve 'mach build' notifications. r=gps (2c65a122d1)
- Bug 1184696 - Add clobber targets to |mach clobber|; Ability to clobber compiled python files, r=gps (35d8be292e)
- Bug 1117958 - Allow any debugging options to the run or gtest mach subcommands to automatically enable debugging. r=gps (32f986af4b)
- Bug 1180081 - Properly rebuild gtest/libxul before running gtests. r=gps (80db9a3d49)
- Bug 1171647, part 1 - Define a new function to convert the mode to a string. r=njn (61ad16f5ba)
- Bug 1171647, part 2 - Remove redundant assertion for dark matter mode. r=njn (b5ac9519f3)
- Bug 1058178, part 1 - Implement DMD heap scanning mode. r=njn (60e1079536)
- Bug 1058178, part 2 - Implement address clamping analysis for DMD scan logs. r=njn (45c0326b93)
- Bug 1102388 - Fix DMD static constructor ordering dependency. r=mccr8 (59b87897a1)
- Bug 1128705 - Don't redefine PAGE_SIZE in DMD if it's already defined. r=erahm (49216348ee)
- Bug 1179042 - Add a script for analyzing memory blocks using a heap scan DMD log. r=njn DONTBUILD (1c08d2d66e)
- Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat (1c999d139b)
- Bug 1158772 - fix non-idiomatic memset call in nsDeque.cpp; r=erahm (de6b555245)
- Bug 1199400 - Part 1: Use CheckedInt when growing nsDeque capacity. r=froydnj (dfdf6814a3)
- Bug 1199400 - Part 0: Remove unused nsDequeIterator. r=froydnj (38d69d7f47)
- Bug 1199400 - Part 2: Add tests for possible nsDeque corner cases. r=froydnj (931baff195)
- Bug 1201997 - Part 1 - Converted compiled test to gtest for nsDeque class. Added tests to test untested methods. r=froydn (e893916651)
- Bug 1201997 - Part 2 - Removing unused methods from the nsDeque class. r=froydn (41595a90ac)
- Bug 1201997 - Part 3 - Make internally used methods private. r=froydn (8cd3afd96f)
- Bug 1201997 - Part 4 - Change size and offset variables to size_t.r=froydn (73eabc8d60)
- Bug 1215140 P1 Add an nsIConsoleReportCollector interface to support navigation channel logging. r=bz (8a41535e2b)
- Bug 1215140 P2 Make HttpBaseChannel implement nsIConsoleReportCollector. r=bz (75fca301f2)
- Bug 1197679 - If nsUnknownDecoder is involved in e10s DivertToParent can break. r=jduell (5d94a12504)
- Bug 1178991 - smartptr for http converter r=hurley (8e7fbc8443)
- bug 366559 - patch 2, fix nsHTTPCompressConv indentation r=bagder (ba762da587)
- bug 366559 - patch 3, fix nsHTTPCompressConv bracing style r=bagder (54195ab451)
- bits of bug 366559 - patch 7, content-encoding brotli for http (f0b4051022)
- Bug 1205112 - Make PushEvent.data nullable. r=mt,smaug (775db32856)
- Bug 1193414 - SharedWorkers thread should be kept alive also when the SharedWorker object is CCed, r=khuey (b77ea8125c)
- Bug 1206520: Add about:config prefs to enable throwing on asm.js validation failures; r=bz (c42126665d)
- Bug 1193414 - Telemetry for SharedWorker spawning. r=bkelly (77984b7bcc)
- Bug 1205676 - Enable WPT service-worker/unregister-then-register-new-script.https.html in e10s, r=nsm (ec24939cf6)
- Bug 1193133 - Throw when calling postMessage from a Service Worker dom object with no global. r=bkelly (526dcacfab)
- Bug 1181871 P1 Only enforce Cache Context shared data destruction on target thread after init. r=ehsan (cdbf3ed3a8)
- Bug 1181871 P2 Fix ServiceWorkerManager usage of stack-based ErrorResult. r=ehsan (c449195d90)
- minor cleanup and missing bit of 1198230 (02f459db05)
- Bug 1143717 - Implement the ServiceWorkerMessageEvent interface. r=baku (027b3465f2)
- fix misspatch (708eee4e84)
- Bug 1188545 - Disentangle service workers from shared workers and refactor event dispatching code into a separate class. r=nsm,mrbkap (fb5b5341c9)
- Bug 1205228 - Change PackagedAppVerifier to notify the verification result asynchronously. r=valentin. (9edda0fa00)
- Bug 1178518 - Packaged App Utils. r=valentin (f60f3b7a93)
- Bug 1213150 - Part 1: Add a nsContentUtils::IsNonSubresourceRequest helper; r=jdm (b509cc3cc9)
- Bug 1213150 - Part 2: Rework ShouldPrepareForIntercept() in terms of subresource requests; r=jdm (2e92fe8780)
- Bug 1213150 - Part 3: Remove nsIInterceptedChannel.isNavigation; r=jdm (becf1cc12f)
- Bug 1213150 follow-up: fix build bustage (8d73d6ca73)
- Bug 1198394 - Part 1: Allow interception of HSTS upgraded connections in non-e10s mode; r=mcmanus (f504c5be08)
- Bug 1198394 - Part 2: Add a test for interception of HSTS upgraded connections; r=jdm (054e984eef)
- Bug 1187011 - Don't allow response body with null body status. r=bkelly (b1860741d1)
- missing bit of 1140788 (29d319712e)
- Bug 1213436 - Reject core dumps with node IDs that don't fit in an IEEE 754 double; r=sfink (3c1f6fdda0)
- Bug 1211006 - Add Debugger.Source.prototype.canonicalId; r=ejpbruel (eef7b79fce)
- Bug 1199218 - Implement JS::ubi::Node::size for js::LazyScript referents; r=sfink (098a48d240)
- Bug 1220031 - Add JS::ubi::Node::scriptFilename; r=sfink (6b824ae680)
- Bug 1143575. Remove unused MediaQueue::Empty. r=cpearce (de737f3433)
- Bug 1209933 - Make sure all parent runtime pointers are the topmost parent, r=billm. (fe824d967d)
- Bug 1197012 - Fix ThrowTypeError in Notification. r=mccr8 (0b1a097526)
- Bug 1197893 - Check the number of arguments for ThrowTypeError() and ThrowRangeError() at compile time. r=peterv (d98c7d78a0)
- Bug 1142083 - Add test for IDN Unicode domain redirect. r=mcmanus (0c8961fe17)
- Bug 1187159 - Add mochitest for loading packaged apps (iframe+fetch+mozapp) r=jduell (ce90ea561b)
- Bug 1186290 - Notify TabParent to switch process when loading a signed package. r=honzab, r=kanru. (c58a14554a)
- fix (15e2df75eb)
- Bug 1206124 P1 Fix "same-origin" CORS credentials in FetchDriver. r=ehsan (fae1bb6ab3)
- Bug 1206124 P2 Test fetch() with credentials and redirects. r=ehsan (ffc6254112)
- Bug 1211751: Remove nsIChannelEventSink-forwarding from EventSource and FetchDriver. It's never needed. r=smaug (adafe5737a)
- Bug 1212433 Fail fetch() calls that require preflight and also redirect. r=sicking a=abillings (c0d6742b9e)
- Bug 1193128 - Fix base64 decoding when fetching data URIs. r=baku (80bafa291a)
- Bug 1195167 part 1: Let necko handle all protocols. r=bkelly (bb932b0ada)
- Bug 1195167 part 2: Remove redundant aCORSFlag argument and instead use mCORSFlagEverSet. r=bkelly (beadafcad0)
- Bug 1195167 part 3: Remove more scheme-specific handling from FetchDriver. r=bkelly (d00b38db9e)
- Bug 1195167 part 4: Remove FetchDriver::BasicFetch since it is empty. r=bkelly (c5ed097267)
- Bug 1210413 P2 Test CORS credentials on cross-origin redirects. r=sicking a=dveditz (b4eeb8aac0)
- Bug 1210413 P1 Propagate new channel load flags from child to parent on redirect. r=jduell a=dveditz (8b329af4fa)
- Bug 1195167 part 5: Make FetchDriver use AsyncOpen2. r=bkelly (cc217c4cc1)
- Bug 1195167 part 6: Some code simplification since necko handles fetch recursion. r=bkelly (f3b6da2262)
- Bug 1195167: Followup to fix test which I forgot to change (81e7439a2e)
- Bug 1215746: Remove RequestMode::Cors_with_forced_preflight. r=bkelly (0336e812b6)
- Bug 1211000: Move CORS preflight logic from nsCORSListenerProxy to nsCORSPreflightListener. r=ehsan (bf2f71cf22)
- missing bit of Bug 1211443 - Drop scheduled update if decoder initialization isn't done yet. r=jya (f6bc074e33)
- Bug 1182571: Fix nsILoadInfo->GetContentPolicyType API to be less ambigious. Audit and fix all users of it. r=ckerschb (5af6fa7442)
- fix (e40c8e7625)
- Bug 1173811 - Part 1: Propagate the response URL to intercepted channels when necessary (non-e10s). r=mayhemer,bkelly (26f4f13c28)
- Bug 1173811 - Part 2: Propagate the response URL to intercepted channels when necessary (e10s). r=mayhemer,bkelly (a603fe1df2)
- Bug 1154309 - Add New Resource Timing Fields r=bz,hurley (1d14eb6bef)
- Bug 1175685 - add OriginAttribute to LoadInfo. r=jonas, r=ckerschb, r=michal (a5d18bb637)
- Bug 1175685 - add OriginAttribute to LoadInfo. r=jonas, r=ckerschb, r=michal (fb07d2c8aa)
- Bug 1212904 P1 Add a LoadTainting enumeration. r=jduell (a1db8a3e99)
- Bug 1212904 P2 Add LoadTainting information to nsILoadInfo. r=jduell (2482e5e334)
- Bug 1221151 - use [infallible] in nsILoadInfo.idl instead of manual %{C++ blocks; r=jduell (aae73129b6)
- Bug 1045891 - CSP 2 child-src implementation r=ckerschb (792920aeb9)
- Bug 1219931 - CSP: Don't allow removing a policy (r=sicking) (9daaab4186)
- Bug 1208661 - Dump client-side layer textures. r=BenWa (1f2d17d515)
499 lines
16 KiB
C++
499 lines
16 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "nsLineBreaker.h"
|
|
#include "nsContentUtils.h"
|
|
#include "nsILineBreaker.h"
|
|
#include "gfxTextRun.h" // for the gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_* values
|
|
#include "nsHyphenationManager.h"
|
|
#include "nsHyphenator.h"
|
|
#include "mozilla/gfx/2D.h"
|
|
|
|
nsLineBreaker::nsLineBreaker()
|
|
: mCurrentWordLanguage(nullptr),
|
|
mCurrentWordContainsMixedLang(false),
|
|
mCurrentWordContainsComplexChar(false),
|
|
mAfterBreakableSpace(false), mBreakHere(false),
|
|
mWordBreak(nsILineBreaker::kWordBreak_Normal)
|
|
{
|
|
}
|
|
|
|
nsLineBreaker::~nsLineBreaker()
|
|
{
|
|
NS_ASSERTION(mCurrentWord.Length() == 0, "Should have Reset() before destruction!");
|
|
}
|
|
|
|
static void
|
|
SetupCapitalization(const char16_t* aWord, uint32_t aLength,
|
|
bool* aCapitalization)
|
|
{
|
|
// Capitalize the first alphanumeric character after a space or start
|
|
// of the word.
|
|
// The only space character a word can contain is NBSP.
|
|
bool capitalizeNextChar = true;
|
|
for (uint32_t i = 0; i < aLength; ++i) {
|
|
uint32_t ch = aWord[i];
|
|
if (capitalizeNextChar) {
|
|
if (NS_IS_HIGH_SURROGATE(ch) && i + 1 < aLength &&
|
|
NS_IS_LOW_SURROGATE(aWord[i + 1])) {
|
|
ch = SURROGATE_TO_UCS4(ch, aWord[i + 1]);
|
|
}
|
|
if (nsContentUtils::IsAlphanumeric(ch)) {
|
|
aCapitalization[i] = true;
|
|
capitalizeNextChar = false;
|
|
}
|
|
if (!IS_IN_BMP(ch)) {
|
|
++i;
|
|
}
|
|
}
|
|
if (ch == 0xA0 /*NBSP*/) {
|
|
capitalizeNextChar = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
nsresult
|
|
nsLineBreaker::FlushCurrentWord()
|
|
{
|
|
uint32_t length = mCurrentWord.Length();
|
|
nsAutoTArray<uint8_t,4000> breakState;
|
|
if (!breakState.AppendElements(length))
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
nsTArray<bool> capitalizationState;
|
|
|
|
if (!mCurrentWordContainsComplexChar) {
|
|
// For break-strict set everything internal to "break", otherwise
|
|
// to "no break"!
|
|
memset(breakState.Elements(),
|
|
mWordBreak == nsILineBreaker::kWordBreak_BreakAll ?
|
|
gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NORMAL :
|
|
gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE,
|
|
length*sizeof(uint8_t));
|
|
} else {
|
|
nsContentUtils::LineBreaker()->
|
|
GetJISx4051Breaks(mCurrentWord.Elements(), length, mWordBreak,
|
|
breakState.Elements());
|
|
}
|
|
|
|
bool autoHyphenate = mCurrentWordLanguage &&
|
|
!mCurrentWordContainsMixedLang;
|
|
uint32_t i;
|
|
for (i = 0; autoHyphenate && i < mTextItems.Length(); ++i) {
|
|
TextItem* ti = &mTextItems[i];
|
|
if (!(ti->mFlags & BREAK_USE_AUTO_HYPHENATION)) {
|
|
autoHyphenate = false;
|
|
}
|
|
}
|
|
if (autoHyphenate) {
|
|
RefPtr<nsHyphenator> hyphenator =
|
|
nsHyphenationManager::Instance()->GetHyphenator(mCurrentWordLanguage);
|
|
if (hyphenator) {
|
|
FindHyphenationPoints(hyphenator,
|
|
mCurrentWord.Elements(),
|
|
mCurrentWord.Elements() + length,
|
|
breakState.Elements());
|
|
}
|
|
}
|
|
|
|
uint32_t offset = 0;
|
|
for (i = 0; i < mTextItems.Length(); ++i) {
|
|
TextItem* ti = &mTextItems[i];
|
|
NS_ASSERTION(ti->mLength > 0, "Zero length word contribution?");
|
|
|
|
if ((ti->mFlags & BREAK_SUPPRESS_INITIAL) && ti->mSinkOffset == 0) {
|
|
breakState[offset] = gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE;
|
|
}
|
|
if (ti->mFlags & BREAK_SUPPRESS_INSIDE) {
|
|
uint32_t exclude = ti->mSinkOffset == 0 ? 1 : 0;
|
|
memset(breakState.Elements() + offset + exclude,
|
|
gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE,
|
|
(ti->mLength - exclude)*sizeof(uint8_t));
|
|
}
|
|
|
|
// Don't set the break state for the first character of the word, because
|
|
// it was already set correctly earlier and we don't know what the true
|
|
// value should be.
|
|
uint32_t skipSet = i == 0 ? 1 : 0;
|
|
if (ti->mSink) {
|
|
ti->mSink->SetBreaks(ti->mSinkOffset + skipSet, ti->mLength - skipSet,
|
|
breakState.Elements() + offset + skipSet);
|
|
|
|
if (ti->mFlags & BREAK_NEED_CAPITALIZATION) {
|
|
if (capitalizationState.Length() == 0) {
|
|
if (!capitalizationState.AppendElements(length))
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
memset(capitalizationState.Elements(), false, length*sizeof(bool));
|
|
SetupCapitalization(mCurrentWord.Elements(), length,
|
|
capitalizationState.Elements());
|
|
}
|
|
ti->mSink->SetCapitalization(ti->mSinkOffset, ti->mLength,
|
|
capitalizationState.Elements() + offset);
|
|
}
|
|
}
|
|
|
|
offset += ti->mLength;
|
|
}
|
|
|
|
mCurrentWord.Clear();
|
|
mTextItems.Clear();
|
|
mCurrentWordContainsComplexChar = false;
|
|
mCurrentWordContainsMixedLang = false;
|
|
mCurrentWordLanguage = nullptr;
|
|
return NS_OK;
|
|
}
|
|
|
|
// If the aFlags parameter to AppendText has all these bits set,
|
|
// then we don't need to worry about finding break opportunities
|
|
// in the appended text.
|
|
#define NO_BREAKS_NEEDED_FLAGS (BREAK_SUPPRESS_INITIAL | \
|
|
BREAK_SUPPRESS_INSIDE | \
|
|
BREAK_SKIP_SETTING_NO_BREAKS)
|
|
|
|
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;
|
|
}
|
|
|
|
nsAutoTArray<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;
|
|
}
|
|
|
|
void
|
|
nsLineBreaker::FindHyphenationPoints(nsHyphenator *aHyphenator,
|
|
const char16_t *aTextStart,
|
|
const char16_t *aTextLimit,
|
|
uint8_t *aBreakState)
|
|
{
|
|
nsDependentSubstring string(aTextStart, aTextLimit);
|
|
AutoFallibleTArray<bool,200> hyphens;
|
|
if (NS_SUCCEEDED(aHyphenator->Hyphenate(string, hyphens))) {
|
|
for (uint32_t i = 0; i + 1 < string.Length(); ++i) {
|
|
if (hyphens[i]) {
|
|
aBreakState[i + 1] =
|
|
gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_HYPHEN;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
nsresult
|
|
nsLineBreaker::AppendText(nsIAtom* aHyphenationLanguage, const uint8_t* aText, uint32_t aLength,
|
|
uint32_t 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(aHyphenationLanguage, str.get(), aLength, aFlags, aSink);
|
|
}
|
|
|
|
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 &&
|
|
IsComplexASCIIChar(aText[offset])) {
|
|
mCurrentWordContainsComplexChar = 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<uint8_t,4000> breakState;
|
|
if (aSink) {
|
|
if (!breakState.AppendElements(aLength))
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
uint32_t start = offset;
|
|
bool noBreaksNeeded = !aSink ||
|
|
((aFlags & NO_BREAKS_NEEDED_FLAGS) == NO_BREAKS_NEEDED_FLAGS &&
|
|
!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;
|
|
}
|
|
}
|
|
uint32_t wordStart = offset;
|
|
bool wordHasComplexChar = false;
|
|
|
|
for (;;) {
|
|
uint8_t ch = aText[offset];
|
|
bool isSpace = IsSpace(ch);
|
|
bool isBreakableSpace = isSpace && !(aFlags & BREAK_SUPPRESS_INSIDE);
|
|
|
|
if (aSink) {
|
|
// Consider word-break style. Since the break position of CJK scripts
|
|
// will be set by nsILineBreaker, we don't consider CJK at this point.
|
|
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 && wordHasComplexChar) {
|
|
if (aSink && !(aFlags & BREAK_SUPPRESS_INSIDE)) {
|
|
// 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;
|
|
}
|
|
wordHasComplexChar = false;
|
|
}
|
|
|
|
++offset;
|
|
if (offset >= aLength)
|
|
break;
|
|
wordStart = offset;
|
|
} else {
|
|
if (!wordHasComplexChar && IsComplexASCIIChar(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;
|
|
uint32_t 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;
|
|
}
|
|
|
|
void
|
|
nsLineBreaker::UpdateCurrentWordLanguage(nsIAtom *aHyphenationLanguage)
|
|
{
|
|
if (mCurrentWordLanguage && mCurrentWordLanguage != aHyphenationLanguage) {
|
|
mCurrentWordContainsMixedLang = true;
|
|
} else {
|
|
mCurrentWordLanguage = aHyphenationLanguage;
|
|
}
|
|
}
|
|
|
|
nsresult
|
|
nsLineBreaker::AppendInvisibleWhitespace(uint32_t aFlags)
|
|
{
|
|
nsresult rv = FlushCurrentWord();
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
bool isBreakableSpace = !(aFlags & BREAK_SUPPRESS_INSIDE);
|
|
if (mAfterBreakableSpace && !isBreakableSpace) {
|
|
mBreakHere = true;
|
|
}
|
|
mAfterBreakableSpace = isBreakableSpace;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsLineBreaker::Reset(bool* aTrailingBreak)
|
|
{
|
|
nsresult rv = FlushCurrentWord();
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
*aTrailingBreak = mBreakHere || mAfterBreakableSpace;
|
|
mBreakHere = false;
|
|
mAfterBreakableSpace = false;
|
|
return NS_OK;
|
|
}
|