Fixed textfield rendering in nsNativeThemeQt
[mozilla-central.git] / layout / generic / nsTextFrameUtils.cpp
blobab2930ca210ac74a670514fe4dd9519053712944
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
13 * License.
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.
21 * Contributor(s):
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"
42 #include "gfxFont.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.
59 if (ch == CH_SHY) {
60 *aFlags |= nsTextFrameUtils::TEXT_HAS_SHY;
61 return PR_TRUE;
63 if ((ch & 0xFF00) != 0x2000) {
64 // Not a Bidi control character
65 return PR_FALSE;
67 return IS_BIDI_CONTROL_CHAR(ch);
70 static PRBool IsDiscardable(PRUint8 ch, PRUint32* aFlags)
72 if (ch == CH_SHY) {
73 *aFlags |= nsTextFrameUtils::TEXT_HAS_SHY;
74 return PR_TRUE;
76 return PR_FALSE;
79 PRUnichar*
80 nsTextFrameUtils::TransformText(const PRUnichar* aText, PRUint32 aLength,
81 PRUnichar* aOutput,
82 PRBool aCompressWhitespace,
83 PRPackedBool* aIncomingWhitespace,
84 gfxSkipCharsBuilder* aSkipChars,
85 PRUint32* aAnalysisFlags)
87 PRUint32 flags = 0;
88 PRUnichar* outputStart = aOutput;
90 if (!aCompressWhitespace) {
91 // Skip discardables.
92 PRUint32 i;
93 for (i = 0; i < aLength; ++i) {
94 PRUnichar ch = *aText++;
95 if (IsDiscardable(ch, &flags)) {
96 aSkipChars->SkipChar();
97 } else {
98 aSkipChars->KeepChar();
99 if (ch == '\t') {
100 flags |= TEXT_HAS_TAB;
102 *aOutput++ = ch;
105 *aIncomingWhitespace = PR_FALSE;
106 } else {
107 PRBool inWhitespace = *aIncomingWhitespace;
108 PRUint32 i;
109 for (i = 0; i < aLength; ++i) {
110 PRUnichar ch = *aText++;
111 PRBool nowInWhitespace;
112 if (ch == ' ' &&
113 (i + 1 >= aLength ||
114 !IsSpaceCombiningSequenceTail(aText, aLength - (i + 1)))) {
115 nowInWhitespace = PR_TRUE;
116 } else if (ch == '\n') {
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();
122 continue;
124 nowInWhitespace = PR_TRUE;
125 } else {
126 nowInWhitespace = ch == '\t';
129 if (!nowInWhitespace) {
130 if (IsDiscardable(ch, &flags)) {
131 aSkipChars->SkipChar();
132 nowInWhitespace = inWhitespace;
133 } else {
134 *aOutput++ = ch;
135 aSkipChars->KeepChar();
137 } else {
138 if (inWhitespace) {
139 aSkipChars->SkipChar();
140 } else {
141 if (ch != ' ') {
142 flags |= TEXT_WAS_TRANSFORMED;
144 *aOutput++ = ' ';
145 aSkipChars->KeepChar();
148 inWhitespace = nowInWhitespace;
150 *aIncomingWhitespace = inWhitespace;
153 if (outputStart + aLength != aOutput) {
154 flags |= TEXT_WAS_TRANSFORMED;
156 *aAnalysisFlags = flags;
157 return aOutput;
160 PRUint8*
161 nsTextFrameUtils::TransformText(const PRUint8* aText, PRUint32 aLength,
162 PRUint8* aOutput,
163 PRBool aCompressWhitespace,
164 PRPackedBool* aIncomingWhitespace,
165 gfxSkipCharsBuilder* aSkipChars,
166 PRUint32* aAnalysisFlags)
168 PRUint32 flags = 0;
169 PRUint8* outputStart = aOutput;
171 if (!aCompressWhitespace) {
172 // Skip discardables.
173 PRUint32 i;
174 for (i = 0; i < aLength; ++i) {
175 PRUint8 ch = *aText++;
176 if (IsDiscardable(ch, &flags)) {
177 aSkipChars->SkipChar();
178 } else {
179 aSkipChars->KeepChar();
180 if (ch == '\t') {
181 flags |= TEXT_HAS_TAB;
183 *aOutput++ = ch;
186 *aIncomingWhitespace = PR_FALSE;
187 } else {
188 PRBool inWhitespace = *aIncomingWhitespace;
189 PRUint32 i;
190 for (i = 0; i < aLength; ++i) {
191 PRUint8 ch = *aText++;
192 PRBool nowInWhitespace = ch == ' ' || ch == '\t' || ch == '\n' || ch == '\f';
193 if (!nowInWhitespace) {
194 if (IsDiscardable(ch, &flags)) {
195 aSkipChars->SkipChar();
196 nowInWhitespace = inWhitespace;
197 } else {
198 *aOutput++ = ch;
199 aSkipChars->KeepChar();
201 } else {
202 if (inWhitespace) {
203 aSkipChars->SkipChar();
204 } else {
205 if (ch != ' ') {
206 flags |= TEXT_WAS_TRANSFORMED;
208 *aOutput++ = ' ';
209 aSkipChars->KeepChar();
212 inWhitespace = nowInWhitespace;
214 *aIncomingWhitespace = inWhitespace;
217 if (outputStart + aLength != aOutput) {
218 flags |= TEXT_WAS_TRANSFORMED;
220 *aAnalysisFlags = flags;
221 return aOutput;
224 PRBool nsSkipCharsRunIterator::NextRun() {
225 do {
226 if (mRunLength) {
227 mIterator.AdvanceOriginal(mRunLength);
228 NS_ASSERTION(mRunLength > 0, "No characters in run (initial length too large?)");
229 if (!mSkipped || mLengthIncludesSkipped) {
230 mRemainingLength -= mRunLength;
233 if (!mRemainingLength)
234 return PR_FALSE;
235 PRInt32 length;
236 mSkipped = mIterator.IsOriginalCharSkipped(&length);
237 mRunLength = PR_MIN(length, mRemainingLength);
238 } while (!mVisitSkipped && mSkipped);
240 return PR_TRUE;