1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is Novell code.
17 * The Initial Developer of the Original Code is Novell Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 2006
19 * the Initial Developer. All Rights Reserved.
22 * robert@ocallahan.org
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #include "nsTextFrameUtils.h"
40 #include "nsContentUtils.h"
41 #include "nsIWordBreaker.h"
43 #include "nsUnicharUtils.h"
44 #include "nsBidiUtils.h"
46 // XXX TODO implement transform of backslash to yen that nsTextTransform does
47 // when requested by PresContext->LanguageSpecificTransformType(). Do it with
48 // a new factory type that just munges the input stream. But first, check
49 // that we really still need this, it's only enabled via a hidden pref
50 // which defaults false...
52 #define UNICODE_ZWSP 0x200B
54 static PRBool
IsDiscardable(PRUnichar ch
, PRUint32
* aFlags
)
56 // Unlike IS_DISCARDABLE, we don't discard \r. \r will be ignored by gfxTextRun
57 // and discarding it would force us to copy text in many cases of preformatted
58 // text containing \r\n.
60 *aFlags
|= nsTextFrameUtils::TEXT_HAS_SHY
;
63 if ((ch
& 0xFF00) != 0x2000) {
64 // Not a Bidi control character
67 return IS_BIDI_CONTROL_CHAR(ch
);
70 static PRBool
IsDiscardable(PRUint8 ch
, PRUint32
* aFlags
)
73 *aFlags
|= nsTextFrameUtils::TEXT_HAS_SHY
;
80 nsTextFrameUtils::TransformText(const PRUnichar
* aText
, PRUint32 aLength
,
82 CompressionMode aCompression
,
83 PRPackedBool
* aIncomingWhitespace
,
84 gfxSkipCharsBuilder
* aSkipChars
,
85 PRUint32
* aAnalysisFlags
)
88 PRUnichar
* outputStart
= aOutput
;
90 if (aCompression
== COMPRESS_NONE
) {
93 for (i
= 0; i
< aLength
; ++i
) {
94 PRUnichar ch
= *aText
++;
95 if (IsDiscardable(ch
, &flags
)) {
96 aSkipChars
->SkipChar();
98 aSkipChars
->KeepChar();
100 flags
|= TEXT_HAS_TAB
;
105 *aIncomingWhitespace
= PR_FALSE
;
107 PRBool inWhitespace
= *aIncomingWhitespace
;
109 for (i
= 0; i
< aLength
; ++i
) {
110 PRUnichar ch
= *aText
++;
111 PRBool nowInWhitespace
;
114 !IsSpaceCombiningSequenceTail(aText
, aLength
- (i
+ 1)))) {
115 nowInWhitespace
= PR_TRUE
;
116 } else if (ch
== '\n' && aCompression
== COMPRESS_WHITESPACE_NEWLINE
) {
117 if (i
> 0 && IS_CJ_CHAR(aText
[-1]) &&
118 i
+ 1 < aLength
&& IS_CJ_CHAR(aText
[1])) {
119 // Discard newlines between CJK chars.
120 // XXX this really requires more context to get right!
121 aSkipChars
->SkipChar();
124 nowInWhitespace
= PR_TRUE
;
126 nowInWhitespace
= ch
== '\t';
129 if (!nowInWhitespace
) {
130 if (IsDiscardable(ch
, &flags
)) {
131 aSkipChars
->SkipChar();
132 nowInWhitespace
= inWhitespace
;
135 aSkipChars
->KeepChar();
139 aSkipChars
->SkipChar();
142 flags
|= TEXT_WAS_TRANSFORMED
;
145 aSkipChars
->KeepChar();
148 inWhitespace
= nowInWhitespace
;
150 *aIncomingWhitespace
= inWhitespace
;
153 if (outputStart
+ aLength
!= aOutput
) {
154 flags
|= TEXT_WAS_TRANSFORMED
;
156 *aAnalysisFlags
= flags
;
161 nsTextFrameUtils::TransformText(const PRUint8
* aText
, PRUint32 aLength
,
163 CompressionMode aCompression
,
164 PRPackedBool
* aIncomingWhitespace
,
165 gfxSkipCharsBuilder
* aSkipChars
,
166 PRUint32
* aAnalysisFlags
)
169 PRUint8
* outputStart
= aOutput
;
171 if (aCompression
== COMPRESS_NONE
) {
172 // Skip discardables.
174 for (i
= 0; i
< aLength
; ++i
) {
175 PRUint8 ch
= *aText
++;
176 if (IsDiscardable(ch
, &flags
)) {
177 aSkipChars
->SkipChar();
179 aSkipChars
->KeepChar();
181 flags
|= TEXT_HAS_TAB
;
186 *aIncomingWhitespace
= PR_FALSE
;
188 PRBool inWhitespace
= *aIncomingWhitespace
;
190 for (i
= 0; i
< aLength
; ++i
) {
191 PRUint8 ch
= *aText
++;
192 PRBool nowInWhitespace
= ch
== ' ' || ch
== '\t' ||
193 (ch
== '\n' && aCompression
== COMPRESS_WHITESPACE_NEWLINE
);
194 if (!nowInWhitespace
) {
195 if (IsDiscardable(ch
, &flags
)) {
196 aSkipChars
->SkipChar();
197 nowInWhitespace
= inWhitespace
;
200 aSkipChars
->KeepChar();
204 aSkipChars
->SkipChar();
207 flags
|= TEXT_WAS_TRANSFORMED
;
210 aSkipChars
->KeepChar();
213 inWhitespace
= nowInWhitespace
;
215 *aIncomingWhitespace
= inWhitespace
;
218 if (outputStart
+ aLength
!= aOutput
) {
219 flags
|= TEXT_WAS_TRANSFORMED
;
221 *aAnalysisFlags
= flags
;
225 PRBool
nsSkipCharsRunIterator::NextRun() {
228 mIterator
.AdvanceOriginal(mRunLength
);
229 NS_ASSERTION(mRunLength
> 0, "No characters in run (initial length too large?)");
230 if (!mSkipped
|| mLengthIncludesSkipped
) {
231 mRemainingLength
-= mRunLength
;
234 if (!mRemainingLength
)
237 mSkipped
= mIterator
.IsOriginalCharSkipped(&length
);
238 mRunLength
= PR_MIN(length
, mRemainingLength
);
239 } while (!mVisitSkipped
&& mSkipped
);