1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef NSTEXTRUNTRANSFORMATIONS_H_
8 #define NSTEXTRUNTRANSFORMATIONS_H_
10 #include "mozilla/Attributes.h"
11 #include "mozilla/MemoryReporting.h"
12 #include "mozilla/UniquePtr.h"
13 #include "gfxTextRun.h"
14 #include "mozilla/ComputedStyle.h"
15 #include "nsPresContext.h"
16 #include "nsStyleStruct.h"
18 class nsTransformedTextRun
;
20 struct nsTransformedCharStyle final
{
21 NS_INLINE_DECL_REFCOUNTING(nsTransformedCharStyle
)
23 explicit nsTransformedCharStyle(mozilla::ComputedStyle
* aStyle
,
24 nsPresContext
* aPresContext
)
25 : mFont(aStyle
->StyleFont()->mFont
),
26 mLanguage(aStyle
->StyleFont()->mLanguage
),
27 mPresContext(aPresContext
),
28 mTextTransform(aStyle
->StyleText()->mTextTransform
),
29 mMathVariant(aStyle
->StyleFont()->mMathVariant
),
30 mExplicitLanguage(aStyle
->StyleFont()->mExplicitLanguage
) {}
33 RefPtr
<nsAtom
> mLanguage
;
34 RefPtr
<nsPresContext
> mPresContext
;
35 mozilla::StyleTextTransform mTextTransform
;
36 mozilla::StyleMathVariant mMathVariant
;
37 bool mExplicitLanguage
;
38 bool mForceNonFullWidth
= false;
39 bool mMaskPassword
= false;
42 ~nsTransformedCharStyle() = default;
43 nsTransformedCharStyle(const nsTransformedCharStyle
& aOther
) = delete;
44 nsTransformedCharStyle
& operator=(const nsTransformedCharStyle
& aOther
) =
48 class nsTransformingTextRunFactory
{
50 virtual ~nsTransformingTextRunFactory() = default;
52 // Default 8-bit path just transforms to Unicode and takes that path
53 already_AddRefed
<nsTransformedTextRun
> MakeTextRun(
54 const uint8_t* aString
, uint32_t aLength
,
55 const gfxFontGroup::Parameters
* aParams
, gfxFontGroup
* aFontGroup
,
56 mozilla::gfx::ShapedTextFlags aFlags
, nsTextFrameUtils::Flags aFlags2
,
57 nsTArray
<RefPtr
<nsTransformedCharStyle
>>&& aStyles
, bool aOwnsFactory
);
59 already_AddRefed
<nsTransformedTextRun
> MakeTextRun(
60 const char16_t
* aString
, uint32_t aLength
,
61 const gfxFontGroup::Parameters
* aParams
, gfxFontGroup
* aFontGroup
,
62 mozilla::gfx::ShapedTextFlags aFlags
, nsTextFrameUtils::Flags aFlags2
,
63 nsTArray
<RefPtr
<nsTransformedCharStyle
>>&& aStyles
, bool aOwnsFactory
);
65 virtual void RebuildTextRun(nsTransformedTextRun
* aTextRun
,
66 mozilla::gfx::DrawTarget
* aRefDrawTarget
,
67 gfxMissingFontRecorder
* aMFR
) = 0;
71 * Builds textruns that transform the text in some way (e.g., capitalize)
72 * and then render the text using some other textrun implementation.
73 * This factory also supports "text-security" transforms that convert all
74 * characters to a single symbol.
76 class nsCaseTransformTextRunFactory
: public nsTransformingTextRunFactory
{
78 // We could add an optimization here so that when there is no inner
79 // factory, no title-case conversion, and no upper-casing of SZLIG, we
80 // override MakeTextRun (after making it virtual in the superclass) and have
81 // it just convert the string to uppercase or lowercase and create the textrun
84 // Takes ownership of aInnerTransformTextRunFactory
85 nsCaseTransformTextRunFactory(mozilla::UniquePtr
<nsTransformingTextRunFactory
>
86 aInnerTransformingTextRunFactory
,
87 bool aAllUppercase
, char16_t aMaskChar
)
88 : mInnerTransformingTextRunFactory(
89 std::move(aInnerTransformingTextRunFactory
)),
90 mAllUppercase(aAllUppercase
),
91 mMaskChar(aMaskChar
) {}
93 virtual void RebuildTextRun(nsTransformedTextRun
* aTextRun
,
94 mozilla::gfx::DrawTarget
* aRefDrawTarget
,
95 gfxMissingFontRecorder
* aMFR
) override
;
97 // Perform a transformation on the given string, writing the result into
98 // aConvertedString. If aGlobalTransform is passed, the transform is global
99 // and aLanguage is used to determine any language-specific behavior;
100 // otherwise, an nsTransformedTextRun should be passed in as aTextRun and its
101 // styles will be used to determine the transform(s) to be applied.
102 // If such an input textrun is provided, then its line-breaks and styles
103 // will be copied to the output arrays, which must also be provided by
104 // the caller. For the global transform usage (no input textrun), these are
106 // If aMaskChar is non-zero, it is used as a "masking" character to replace
107 // all characters in the text (for -webkit-text-security).
108 // If aCaseTransformsOnly is true, then only the upper/lower/capitalize
109 // transformations are performed; full-width and full-size-kana are ignored.
110 // If `aTextRun` is not nullptr and characters which are styled with setting
111 // `nsTransformedCharStyle::mMaskPassword` to true, they are replaced with
112 // password mask characters and are not transformed (i.e., won't be added
113 // or merged for the specified transform). However, unmasked characters
114 // whose `nsTransformedCharStyle::mMaskPassword` is set to false are
115 // transformed normally.
116 // Note that "masking" behavior may be triggered either by
117 // -webkit-text-security, resulting in a non-zero aMaskChar being passed,
118 // or by <input type=password>, which results in the editor code setting
119 // nsTransformedCharStyle::mMaskPassword. (The latter mechanism enables the
120 // editor to temporarily reveal the just-entered character during typing,
121 // whereas simply setting aMaskChar would unconditionally mask all the text.)
122 static bool TransformString(
123 const nsAString
& aString
, nsString
& aConvertedString
,
124 const mozilla::Maybe
<mozilla::StyleTextTransform
>& aGlobalTransform
,
125 char16_t aMaskChar
, bool aCaseTransformsOnly
, const nsAtom
* aLanguage
,
126 nsTArray
<bool>& aCharsToMergeArray
, nsTArray
<bool>& aDeletedCharsArray
,
127 const nsTransformedTextRun
* aTextRun
= nullptr,
128 uint32_t aOffsetInTextRun
= 0,
129 nsTArray
<uint8_t>* aCanBreakBeforeArray
= nullptr,
130 nsTArray
<RefPtr
<nsTransformedCharStyle
>>* aStyleArray
= nullptr);
133 mozilla::UniquePtr
<nsTransformingTextRunFactory
>
134 mInnerTransformingTextRunFactory
;
140 * So that we can reshape as necessary, we store enough information
141 * to fully rebuild the textrun contents.
143 class nsTransformedTextRun final
: public gfxTextRun
{
145 static already_AddRefed
<nsTransformedTextRun
> Create(
146 const gfxTextRunFactory::Parameters
* aParams
,
147 nsTransformingTextRunFactory
* aFactory
, gfxFontGroup
* aFontGroup
,
148 const char16_t
* aString
, uint32_t aLength
,
149 const mozilla::gfx::ShapedTextFlags aFlags
,
150 const nsTextFrameUtils::Flags aFlags2
,
151 nsTArray
<RefPtr
<nsTransformedCharStyle
>>&& aStyles
, bool aOwnsFactory
);
153 ~nsTransformedTextRun() {
159 void SetCapitalization(uint32_t aStart
, uint32_t aLength
,
160 bool* aCapitalization
);
161 virtual bool SetPotentialLineBreaks(Range aRange
,
162 const uint8_t* aBreakBefore
) override
;
164 * Called after SetCapitalization and SetPotentialLineBreaks
165 * are done and before we request any data from the textrun. Also always
166 * called after a Create.
168 void FinishSettingProperties(mozilla::gfx::DrawTarget
* aRefDrawTarget
,
169 gfxMissingFontRecorder
* aMFR
) {
171 mNeedsRebuild
= false;
172 mFactory
->RebuildTextRun(this, aRefDrawTarget
, aMFR
);
176 // override the gfxTextRun impls to account for additional members here
177 virtual size_t SizeOfExcludingThis(
178 mozilla::MallocSizeOf aMallocSizeOf
) override
;
179 virtual size_t SizeOfIncludingThis(
180 mozilla::MallocSizeOf aMallocSizeOf
) override
;
182 nsTransformingTextRunFactory
* mFactory
;
183 nsTArray
<RefPtr
<nsTransformedCharStyle
>> mStyles
;
184 nsTArray
<bool> mCapitalize
;
190 nsTransformedTextRun(const gfxTextRunFactory::Parameters
* aParams
,
191 nsTransformingTextRunFactory
* aFactory
,
192 gfxFontGroup
* aFontGroup
, const char16_t
* aString
,
194 const mozilla::gfx::ShapedTextFlags aFlags
,
195 const nsTextFrameUtils::Flags aFlags2
,
196 nsTArray
<RefPtr
<nsTransformedCharStyle
>>&& aStyles
,
198 : gfxTextRun(aParams
, aLength
, aFontGroup
, aFlags
, aFlags2
),
200 mStyles(std::move(aStyles
)),
201 mString(aString
, aLength
),
202 mOwnsFactory(aOwnsFactory
),
203 mNeedsRebuild(true) {
204 mCharacterGlyphs
= reinterpret_cast<CompressedGlyph
*>(this + 1);
209 * Copy a given textrun, but merge certain characters into a single logical
210 * character. Glyphs for a character are added to the glyph list for the
211 * previous character and then the merged character is eliminated. Visually the
212 * results are identical.
214 * This is used for text-transform:uppercase when we encounter a SZLIG,
215 * whose uppercase form is "SS", or other ligature or precomposed form
216 * that expands to multiple codepoints during case transformation,
217 * and for Greek text when combining diacritics have been deleted.
219 * This function is unable to merge characters when they occur in different
220 * glyph runs. This only happens in tricky edge cases where a character was
221 * decomposed by case-mapping (e.g. there's no precomposed uppercase version
222 * of an accented lowercase letter), and then font-matching caused the
223 * diacritics to be assigned to a different font than the base character.
224 * In this situation, the diacritic(s) get discarded, which is less than
225 * ideal, but they probably weren't going to render very well anyway.
226 * Bug 543200 will improve this by making font-matching operate on entire
227 * clusters instead of individual codepoints.
229 * For simplicity, this produces a textrun containing all DetailedGlyphs,
230 * no simple glyphs. So don't call it unless you really have merging to do.
232 * @param aCharsToMerge when aCharsToMerge[i] is true, this character in aSrc
233 * is merged into the previous character
235 * @param aDeletedChars when aDeletedChars[i] is true, the character at this
236 * position in aDest was deleted (has no corresponding char in aSrc)
238 void MergeCharactersInTextRun(gfxTextRun
* aDest
, gfxTextRun
* aSrc
,
239 const bool* aCharsToMerge
,
240 const bool* aDeletedChars
);
242 gfxTextRunFactory::Parameters
GetParametersForInner(
243 nsTransformedTextRun
* aTextRun
, mozilla::gfx::ShapedTextFlags
* aFlags
,
244 mozilla::gfx::DrawTarget
* aRefDrawTarget
);
246 #endif /*NSTEXTRUNTRANSFORMATIONS_H_*/