DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (d38398e5144e)

VCS Links

nsCaseTransformTextRunFactory

nsTransformedCharStyle

nsTransformedTextRun

nsTransformingTextRunFactory

Macros

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * 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/. */

#ifndef NSTEXTRUNTRANSFORMATIONS_H_
#define NSTEXTRUNTRANSFORMATIONS_H_

#include "mozilla/Attributes.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/UniquePtr.h"
#include "gfxTextRun.h"
#include "nsStyleContext.h"

class nsTransformedTextRun;

struct nsTransformedCharStyle final {
  NS_INLINE_DECL_REFCOUNTING(nsTransformedCharStyle)

  explicit nsTransformedCharStyle(nsStyleContext* aContext)
    : mFont(aContext->StyleFont()->mFont)
    , mLanguage(aContext->StyleFont()->mLanguage)
    , mPresContext(aContext->PresContext())
    , mScriptSizeMultiplier(aContext->StyleFont()->mScriptSizeMultiplier)
    , mTextTransform(aContext->StyleText()->mTextTransform)
    , mMathVariant(aContext->StyleFont()->mMathVariant)
    , mExplicitLanguage(aContext->StyleFont()->mExplicitLanguage) {}

  nsFont                  mFont;
  nsCOMPtr<nsIAtom>       mLanguage;
  RefPtr<nsPresContext> mPresContext;
  float                   mScriptSizeMultiplier;
  uint8_t                 mTextTransform;
  uint8_t                 mMathVariant;
  bool                    mExplicitLanguage;
  bool                    mForceNonFullWidth = false;

private:
  ~nsTransformedCharStyle() {}
  nsTransformedCharStyle(const nsTransformedCharStyle& aOther) = delete;
  nsTransformedCharStyle& operator=(const nsTransformedCharStyle& aOther) = delete;
};

class nsTransformingTextRunFactory {
public:
  virtual ~nsTransformingTextRunFactory() {}

  // Default 8-bit path just transforms to Unicode and takes that path
  already_AddRefed<nsTransformedTextRun>
  MakeTextRun(const uint8_t* aString, uint32_t aLength,
              const gfxFontGroup::Parameters* aParams,
              gfxFontGroup* aFontGroup, uint32_t aFlags,
              nsTArray<RefPtr<nsTransformedCharStyle>>&& aStyles,
              bool aOwnsFactory);

  already_AddRefed<nsTransformedTextRun>
  MakeTextRun(const char16_t* aString, uint32_t aLength,
              const gfxFontGroup::Parameters* aParams,
              gfxFontGroup* aFontGroup, uint32_t aFlags,
              nsTArray<RefPtr<nsTransformedCharStyle>>&& aStyles,
              bool aOwnsFactory);

  virtual void RebuildTextRun(nsTransformedTextRun* aTextRun,
                              mozilla::gfx::DrawTarget* aRefDrawTarget,
                              gfxMissingFontRecorder* aMFR) = 0;
};

/**
 * Builds textruns that transform the text in some way (e.g., capitalize)
 * and then render the text using some other textrun implementation.
 */
class nsCaseTransformTextRunFactory : public nsTransformingTextRunFactory {
public:
  // We could add an optimization here so that when there is no inner
  // factory, no title-case conversion, and no upper-casing of SZLIG, we override
  // MakeTextRun (after making it virtual in the superclass) and have it
  // just convert the string to uppercase or lowercase and create the textrun
  // via the fontgroup.
  
  // Takes ownership of aInnerTransformTextRunFactory
  explicit nsCaseTransformTextRunFactory(mozilla::UniquePtr<nsTransformingTextRunFactory> aInnerTransformingTextRunFactory,
                                         bool aAllUppercase = false)
    : mInnerTransformingTextRunFactory(Move(aInnerTransformingTextRunFactory)),
      mAllUppercase(aAllUppercase) {}

  virtual void RebuildTextRun(nsTransformedTextRun* aTextRun,
                              mozilla::gfx::DrawTarget* aRefDrawTarget,
                              gfxMissingFontRecorder* aMFR) override;

  // Perform a transformation on the given string, writing the result into
  // aConvertedString. If aAllUppercase is true, the transform is (global)
  // upper-casing, and aLanguage is used to determine any language-specific
  // behavior; otherwise, an nsTransformedTextRun should be passed in
  // as aTextRun and its styles will be used to determine the transform(s)
  // to be applied.
  // If such an input textrun is provided, then its line-breaks and styles
  // will be copied to the output arrays, which must also be provided by
  // the caller. For the global upper-casing usage (no input textrun),
  // these are ignored.
  static bool TransformString(const nsAString& aString,
                              nsString& aConvertedString,
                              bool aAllUppercase,
                              const nsIAtom* aLanguage,
                              nsTArray<bool>& aCharsToMergeArray,
                              nsTArray<bool>& aDeletedCharsArray,
                              const nsTransformedTextRun* aTextRun = nullptr,
                              uint32_t aOffsetInTextRun = 0,
                              nsTArray<uint8_t>* aCanBreakBeforeArray = nullptr,
                              nsTArray<RefPtr<nsTransformedCharStyle>>* aStyleArray = nullptr);

protected:
  mozilla::UniquePtr<nsTransformingTextRunFactory> mInnerTransformingTextRunFactory;
  bool mAllUppercase;
};

/**
 * So that we can reshape as necessary, we store enough information
 * to fully rebuild the textrun contents.
 */
class nsTransformedTextRun final : public gfxTextRun {
public:

  static already_AddRefed<nsTransformedTextRun>
  Create(const gfxTextRunFactory::Parameters* aParams,
         nsTransformingTextRunFactory* aFactory,
         gfxFontGroup* aFontGroup,
         const char16_t* aString, uint32_t aLength,
         const uint32_t aFlags,
         nsTArray<RefPtr<nsTransformedCharStyle>>&& aStyles,
         bool aOwnsFactory);

  ~nsTransformedTextRun() {
    if (mOwnsFactory) {
      delete mFactory;
    }
  }
  
  void SetCapitalization(uint32_t aStart, uint32_t aLength,
                         bool* aCapitalization);
  virtual bool SetPotentialLineBreaks(Range aRange,
                                      const uint8_t* aBreakBefore);
  /**
   * Called after SetCapitalization and SetPotentialLineBreaks
   * are done and before we request any data from the textrun. Also always
   * called after a Create.
   */
  void FinishSettingProperties(mozilla::gfx::DrawTarget* aRefDrawTarget,
                               gfxMissingFontRecorder* aMFR)
  {
    if (mNeedsRebuild) {
      mNeedsRebuild = false;
      mFactory->RebuildTextRun(this, aRefDrawTarget, aMFR);
    }
  }

  // override the gfxTextRun impls to account for additional members here
  virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) MOZ_MUST_OVERRIDE;
  virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) MOZ_MUST_OVERRIDE;

  nsTransformingTextRunFactory       *mFactory;
  nsTArray<RefPtr<nsTransformedCharStyle>> mStyles;
  nsTArray<bool>                      mCapitalize;
  nsString                            mString;
  bool                                mOwnsFactory;
  bool                                mNeedsRebuild;

private:
  nsTransformedTextRun(const gfxTextRunFactory::Parameters* aParams,
                       nsTransformingTextRunFactory* aFactory,
                       gfxFontGroup* aFontGroup,
                       const char16_t* aString, uint32_t aLength,
                       const uint32_t aFlags,
                       nsTArray<RefPtr<nsTransformedCharStyle>>&& aStyles,
                       bool aOwnsFactory)
    : gfxTextRun(aParams, aLength, aFontGroup, aFlags),
      mFactory(aFactory), mStyles(aStyles), mString(aString, aLength),
      mOwnsFactory(aOwnsFactory), mNeedsRebuild(true)
  {
    mCharacterGlyphs = reinterpret_cast<CompressedGlyph*>(this + 1);
  }
};

/**
 * Copy a given textrun, but merge certain characters into a single logical
 * character. Glyphs for a character are added to the glyph list for the previous
 * character and then the merged character is eliminated. Visually the results
 * are identical.
 *
 * This is used for text-transform:uppercase when we encounter a SZLIG,
 * whose uppercase form is "SS", or other ligature or precomposed form
 * that expands to multiple codepoints during case transformation,
 * and for Greek text when combining diacritics have been deleted.
 *
 * This function is unable to merge characters when they occur in different
 * glyph runs. This only happens in tricky edge cases where a character was
 * decomposed by case-mapping (e.g. there's no precomposed uppercase version
 * of an accented lowercase letter), and then font-matching caused the
 * diacritics to be assigned to a different font than the base character.
 * In this situation, the diacritic(s) get discarded, which is less than
 * ideal, but they probably weren't going to render very well anyway.
 * Bug 543200 will improve this by making font-matching operate on entire
 * clusters instead of individual codepoints.
 *
 * For simplicity, this produces a textrun containing all DetailedGlyphs,
 * no simple glyphs. So don't call it unless you really have merging to do.
 *
 * @param aCharsToMerge when aCharsToMerge[i] is true, this character in aSrc
 * is merged into the previous character
 *
 * @param aDeletedChars when aDeletedChars[i] is true, the character at this
 * position in aDest was deleted (has no corresponding char in aSrc)
 */
void
MergeCharactersInTextRun(gfxTextRun* aDest, gfxTextRun* aSrc,
                         const bool* aCharsToMerge, const bool* aDeletedChars);

gfxTextRunFactory::Parameters
GetParametersForInner(nsTransformedTextRun* aTextRun, uint32_t* aFlags,
                      mozilla::gfx::DrawTarget* aRefDrawTarget);


#endif /*NSTEXTRUNTRANSFORMATIONS_H_*/