Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/generic/nsTextRunTransformations.h
Line
Count
Source (jump to first uncovered line)
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/. */
6
7
#ifndef NSTEXTRUNTRANSFORMATIONS_H_
8
#define NSTEXTRUNTRANSFORMATIONS_H_
9
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"
17
18
class nsTransformedTextRun;
19
20
struct nsTransformedCharStyle final {
21
  NS_INLINE_DECL_REFCOUNTING(nsTransformedCharStyle)
22
23
  explicit nsTransformedCharStyle(mozilla::ComputedStyle* aStyle,
24
                                  nsPresContext* aPresContext)
25
    : mFont(aStyle->StyleFont()->mFont)
26
    , mLanguage(aStyle->StyleFont()->mLanguage)
27
    , mPresContext(aPresContext)
28
    , mScriptSizeMultiplier(aStyle->StyleFont()->mScriptSizeMultiplier)
29
    , mTextTransform(aStyle->StyleText()->mTextTransform)
30
    , mMathVariant(aStyle->StyleFont()->mMathVariant)
31
0
    , mExplicitLanguage(aStyle->StyleFont()->mExplicitLanguage) {}
32
33
  nsFont                  mFont;
34
  RefPtr<nsAtom>          mLanguage;
35
  RefPtr<nsPresContext>   mPresContext;
36
  float                   mScriptSizeMultiplier;
37
  uint8_t                 mTextTransform;
38
  uint8_t                 mMathVariant;
39
  bool                    mExplicitLanguage;
40
  bool                    mForceNonFullWidth = false;
41
42
private:
43
0
  ~nsTransformedCharStyle() {}
44
  nsTransformedCharStyle(const nsTransformedCharStyle& aOther) = delete;
45
  nsTransformedCharStyle& operator=(const nsTransformedCharStyle& aOther) = delete;
46
};
47
48
class nsTransformingTextRunFactory {
49
public:
50
0
  virtual ~nsTransformingTextRunFactory() {}
51
52
  // Default 8-bit path just transforms to Unicode and takes that path
53
  already_AddRefed<nsTransformedTextRun>
54
  MakeTextRun(const uint8_t* aString, uint32_t aLength,
55
              const gfxFontGroup::Parameters* aParams,
56
              gfxFontGroup* aFontGroup,
57
              mozilla::gfx::ShapedTextFlags aFlags,
58
              nsTextFrameUtils::Flags aFlags2,
59
              nsTArray<RefPtr<nsTransformedCharStyle>>&& aStyles,
60
              bool aOwnsFactory);
61
62
  already_AddRefed<nsTransformedTextRun>
63
  MakeTextRun(const char16_t* aString, uint32_t aLength,
64
              const gfxFontGroup::Parameters* aParams,
65
              gfxFontGroup* aFontGroup,
66
              mozilla::gfx::ShapedTextFlags aFlags,
67
              nsTextFrameUtils::Flags aFlags2,
68
              nsTArray<RefPtr<nsTransformedCharStyle>>&& aStyles,
69
              bool aOwnsFactory);
70
71
  virtual void RebuildTextRun(nsTransformedTextRun* aTextRun,
72
                              mozilla::gfx::DrawTarget* aRefDrawTarget,
73
                              gfxMissingFontRecorder* aMFR) = 0;
74
};
75
76
/**
77
 * Builds textruns that transform the text in some way (e.g., capitalize)
78
 * and then render the text using some other textrun implementation.
79
 */
80
class nsCaseTransformTextRunFactory : public nsTransformingTextRunFactory {
81
public:
82
  // We could add an optimization here so that when there is no inner
83
  // factory, no title-case conversion, and no upper-casing of SZLIG, we override
84
  // MakeTextRun (after making it virtual in the superclass) and have it
85
  // just convert the string to uppercase or lowercase and create the textrun
86
  // via the fontgroup.
87
88
  // Takes ownership of aInnerTransformTextRunFactory
89
  explicit nsCaseTransformTextRunFactory(mozilla::UniquePtr<nsTransformingTextRunFactory> aInnerTransformingTextRunFactory,
90
                                         bool aAllUppercase = false)
91
    : mInnerTransformingTextRunFactory(std::move(aInnerTransformingTextRunFactory)),
92
0
      mAllUppercase(aAllUppercase) {}
93
94
  virtual void RebuildTextRun(nsTransformedTextRun* aTextRun,
95
                              mozilla::gfx::DrawTarget* aRefDrawTarget,
96
                              gfxMissingFontRecorder* aMFR) override;
97
98
  // Perform a transformation on the given string, writing the result into
99
  // aConvertedString. If aAllUppercase is true, the transform is (global)
100
  // upper-casing, and aLanguage is used to determine any language-specific
101
  // behavior; otherwise, an nsTransformedTextRun should be passed in
102
  // as aTextRun and its styles will be used to determine the transform(s)
103
  // to be applied.
104
  // If such an input textrun is provided, then its line-breaks and styles
105
  // will be copied to the output arrays, which must also be provided by
106
  // the caller. For the global upper-casing usage (no input textrun),
107
  // these are ignored.
108
  static bool TransformString(const nsAString& aString,
109
                              nsString& aConvertedString,
110
                              bool aAllUppercase,
111
                              const nsAtom* aLanguage,
112
                              nsTArray<bool>& aCharsToMergeArray,
113
                              nsTArray<bool>& aDeletedCharsArray,
114
                              const nsTransformedTextRun* aTextRun = nullptr,
115
                              uint32_t aOffsetInTextRun = 0,
116
                              nsTArray<uint8_t>* aCanBreakBeforeArray = nullptr,
117
                              nsTArray<RefPtr<nsTransformedCharStyle>>* aStyleArray = nullptr);
118
119
protected:
120
  mozilla::UniquePtr<nsTransformingTextRunFactory> mInnerTransformingTextRunFactory;
121
  bool mAllUppercase;
122
};
123
124
/**
125
 * So that we can reshape as necessary, we store enough information
126
 * to fully rebuild the textrun contents.
127
 */
128
class nsTransformedTextRun final : public gfxTextRun {
129
public:
130
131
  static already_AddRefed<nsTransformedTextRun>
132
  Create(const gfxTextRunFactory::Parameters* aParams,
133
         nsTransformingTextRunFactory* aFactory,
134
         gfxFontGroup* aFontGroup,
135
         const char16_t* aString, uint32_t aLength,
136
         const mozilla::gfx::ShapedTextFlags aFlags,
137
         const nsTextFrameUtils::Flags aFlags2,
138
         nsTArray<RefPtr<nsTransformedCharStyle>>&& aStyles,
139
         bool aOwnsFactory);
140
141
0
  ~nsTransformedTextRun() {
142
0
    if (mOwnsFactory) {
143
0
      delete mFactory;
144
0
    }
145
0
  }
146
147
  void SetCapitalization(uint32_t aStart, uint32_t aLength,
148
                         bool* aCapitalization);
149
  virtual bool SetPotentialLineBreaks(Range aRange,
150
                                      const uint8_t* aBreakBefore) override;
151
  /**
152
   * Called after SetCapitalization and SetPotentialLineBreaks
153
   * are done and before we request any data from the textrun. Also always
154
   * called after a Create.
155
   */
156
  void FinishSettingProperties(mozilla::gfx::DrawTarget* aRefDrawTarget,
157
                               gfxMissingFontRecorder* aMFR)
158
0
  {
159
0
    if (mNeedsRebuild) {
160
0
      mNeedsRebuild = false;
161
0
      mFactory->RebuildTextRun(this, aRefDrawTarget, aMFR);
162
0
    }
163
0
  }
164
165
  // override the gfxTextRun impls to account for additional members here
166
  virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) override;
167
  virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) override;
168
169
  nsTransformingTextRunFactory       *mFactory;
170
  nsTArray<RefPtr<nsTransformedCharStyle>> mStyles;
171
  nsTArray<bool>                      mCapitalize;
172
  nsString                            mString;
173
  bool                                mOwnsFactory;
174
  bool                                mNeedsRebuild;
175
176
private:
177
  nsTransformedTextRun(const gfxTextRunFactory::Parameters* aParams,
178
                       nsTransformingTextRunFactory* aFactory,
179
                       gfxFontGroup* aFontGroup,
180
                       const char16_t* aString, uint32_t aLength,
181
                       const mozilla::gfx::ShapedTextFlags aFlags,
182
                       const nsTextFrameUtils::Flags aFlags2,
183
                       nsTArray<RefPtr<nsTransformedCharStyle>>&& aStyles,
184
                       bool aOwnsFactory)
185
    : gfxTextRun(aParams, aLength, aFontGroup, aFlags, aFlags2),
186
      mFactory(aFactory), mStyles(aStyles), mString(aString, aLength),
187
      mOwnsFactory(aOwnsFactory), mNeedsRebuild(true)
188
0
  {
189
0
    mCharacterGlyphs = reinterpret_cast<CompressedGlyph*>(this + 1);
190
0
  }
191
};
192
193
/**
194
 * Copy a given textrun, but merge certain characters into a single logical
195
 * character. Glyphs for a character are added to the glyph list for the previous
196
 * character and then the merged character is eliminated. Visually the results
197
 * are identical.
198
 *
199
 * This is used for text-transform:uppercase when we encounter a SZLIG,
200
 * whose uppercase form is "SS", or other ligature or precomposed form
201
 * that expands to multiple codepoints during case transformation,
202
 * and for Greek text when combining diacritics have been deleted.
203
 *
204
 * This function is unable to merge characters when they occur in different
205
 * glyph runs. This only happens in tricky edge cases where a character was
206
 * decomposed by case-mapping (e.g. there's no precomposed uppercase version
207
 * of an accented lowercase letter), and then font-matching caused the
208
 * diacritics to be assigned to a different font than the base character.
209
 * In this situation, the diacritic(s) get discarded, which is less than
210
 * ideal, but they probably weren't going to render very well anyway.
211
 * Bug 543200 will improve this by making font-matching operate on entire
212
 * clusters instead of individual codepoints.
213
 *
214
 * For simplicity, this produces a textrun containing all DetailedGlyphs,
215
 * no simple glyphs. So don't call it unless you really have merging to do.
216
 *
217
 * @param aCharsToMerge when aCharsToMerge[i] is true, this character in aSrc
218
 * is merged into the previous character
219
 *
220
 * @param aDeletedChars when aDeletedChars[i] is true, the character at this
221
 * position in aDest was deleted (has no corresponding char in aSrc)
222
 */
223
void
224
MergeCharactersInTextRun(gfxTextRun* aDest, gfxTextRun* aSrc,
225
                         const bool* aCharsToMerge, const bool* aDeletedChars);
226
227
gfxTextRunFactory::Parameters
228
GetParametersForInner(nsTransformedTextRun* aTextRun,
229
                      mozilla::gfx::ShapedTextFlags* aFlags,
230
                      mozilla::gfx::DrawTarget* aRefDrawTarget);
231
232
233
#endif /*NSTEXTRUNTRANSFORMATIONS_H_*/