Attachment #8340708: Part 1: TextFrame and Textrun transformation changes for bug #114365

View | Details | Raw Unified | Return to bug 114365
Collapse All | Expand All

(-)a/layout/generic/MathVariantTextRunFactory.cpp (+662 lines)
Line     Link Here 
Line 0    Link Here 
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2
 * This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "MathVariantTextRunFactory.h"
7
#include "nsStyleConsts.h"
8
#include "nsStyleContext.h"
9
#include "nsTextFrameUtils.h"
10
#include "mozilla/Util.h"
11
12
using namespace mozilla;
13
14
/*
15
  Entries for the mathvariant lookup tables.  mKey represents the Unicode
16
  character to be transformed and is used for searching the tables.
17
  mReplacement represents the mapped mathvariant Unicode character.
18
*/
19
typedef struct
20
{
21
  uint32_t mKey;
22
  uint32_t mReplacement;
23
} MathVarMapping;
24
25
/*
26
 Lookup tables for use with mathvariant mappings to transform a unicode
27
 character point to another unicode character that indicates the proper output.
28
 mKey represents one of two concepts.
29
 1.  In the Latin table it represents a hole in the mathematical alphanumeric
30
     block, where the character that should occupy that position is located
31
     elsewhere.
32
 2.  It represents an Arabic letter.
33
34
  As a replacement, 0 is reserved to indicate no mapping was found.
35
*/
36
static const MathVarMapping gArabicInitialMapTable[] = {
37
  { 0x628, 0x1EE21 },
38
  { 0x62A, 0x1EE35 },
39
  { 0x62B, 0x1EE36 },
40
  { 0x62C, 0x1EE22 },
41
  { 0x62D, 0x1EE27 },
42
  { 0x62E, 0x1EE37 },
43
  { 0x633, 0x1EE2E },
44
  { 0x634, 0x1EE34 },
45
  { 0x635, 0x1EE31 },
46
  { 0x636, 0x1EE39 },
47
  { 0x639, 0x1EE2F },
48
  { 0x63A, 0x1EE3B },
49
  { 0x641, 0x1EE30 },
50
  { 0x642, 0x1EE32 },
51
  { 0x643, 0x1EE2A },
52
  { 0x644, 0x1EE2B },
53
  { 0x645, 0x1EE2C },
54
  { 0x646, 0x1EE2D },
55
  { 0x647, 0x1EE24 },
56
  { 0x64A, 0x1EE29 }
57
};
58
59
static const MathVarMapping gArabicTailedMapTable[] = {
60
  { 0x62C, 0x1EE42 },
61
  { 0x62D, 0x1EE47 },
62
  { 0x62E, 0x1EE57 },
63
  { 0x633, 0x1EE4E },
64
  { 0x634, 0x1EE54 },
65
  { 0x635, 0x1EE51 },
66
  { 0x636, 0x1EE59 },
67
  { 0x639, 0x1EE4F },
68
  { 0x63A, 0x1EE5B },
69
  { 0x642, 0x1EE52 },
70
  { 0x644, 0x1EE4B },
71
  { 0x646, 0x1EE4D },
72
  { 0x64A, 0x1EE49 },
73
  { 0x66F, 0x1EE5F },
74
  { 0x6BA, 0x1EE5D }
75
};
76
77
static const MathVarMapping gArabicStretchedMapTable[] = {
78
  { 0x628, 0x1EE61 },
79
  { 0x62A, 0x1EE75 },
80
  { 0x62B, 0x1EE76 },
81
  { 0x62C, 0x1EE62 },
82
  { 0x62D, 0x1EE67 },
83
  { 0x62E, 0x1EE77 },
84
  { 0x633, 0x1EE6E },
85
  { 0x634, 0x1EE74 },
86
  { 0x635, 0x1EE71 },
87
  { 0x636, 0x1EE79 },
88
  { 0x637, 0x1EE68 },
89
  { 0x638, 0x1EE7A },
90
  { 0x639, 0x1EE6F },
91
  { 0x63A, 0x1EE7B },
92
  { 0x641, 0x1EE70 },
93
  { 0x642, 0x1EE72 },
94
  { 0x643, 0x1EE6A },
95
  { 0x645, 0x1EE6C },
96
  { 0x646, 0x1EE6D },
97
  { 0x647, 0x1EE64 },
98
  { 0x64A, 0x1EE69 },
99
  { 0x66E, 0x1EE7C },
100
  { 0x6A1, 0x1EE7E }
101
};
102
103
static const MathVarMapping gArabicLoopedMapTable[] = {
104
  { 0x627, 0x1EE80 },
105
  { 0x628, 0x1EE81 },
106
  { 0x62A, 0x1EE95 },
107
  { 0x62B, 0x1EE96 },
108
  { 0x62C, 0x1EE82 },
109
  { 0x62D, 0x1EE87 },
110
  { 0x62E, 0x1EE97 },
111
  { 0x62F, 0x1EE83 },
112
  { 0x630, 0x1EE98 },
113
  { 0x631, 0x1EE93 },
114
  { 0x632, 0x1EE86 },
115
  { 0x633, 0x1EE8E },
116
  { 0x634, 0x1EE94 },
117
  { 0x635, 0x1EE91 },
118
  { 0x636, 0x1EE99 },
119
  { 0x637, 0x1EE88 },
120
  { 0x638, 0x1EE9A },
121
  { 0x639, 0x1EE8F },
122
  { 0x63A, 0x1EE9B },
123
  { 0x641, 0x1EE90 },
124
  { 0x642, 0x1EE92 },
125
  { 0x644, 0x1EE8B },
126
  { 0x645, 0x1EE8C },
127
  { 0x646, 0x1EE8D },
128
  { 0x647, 0x1EE84 },
129
  { 0x648, 0x1EE85 },
130
  { 0x64A, 0x1EE89 }
131
};
132
133
static const MathVarMapping gArabicDoubleMapTable[] = {
134
  { 0x628, 0x1EEA1 },
135
  { 0x62A, 0x1EEB5 },
136
  { 0x62B, 0x1EEB6 },
137
  { 0x62C, 0x1EEA2 },
138
  { 0x62D, 0x1EEA7 },
139
  { 0x62E, 0x1EEB7 },
140
  { 0x62F, 0x1EEA3 },
141
  { 0x630, 0x1EEB8 },
142
  { 0x631, 0x1EEB3 },
143
  { 0x632, 0x1EEA6 },
144
  { 0x633, 0x1EEAE },
145
  { 0x634, 0x1EEB4 },
146
  { 0x635, 0x1EEB1 },
147
  { 0x636, 0x1EEB9 },
148
  { 0x637, 0x1EEA8 },
149
  { 0x638, 0x1EEBA },
150
  { 0x639, 0x1EEAF },
151
  { 0x63A, 0x1EEBB },
152
  { 0x641, 0x1EEB0 },
153
  { 0x642, 0x1EEB2 },
154
  { 0x644, 0x1EEAB },
155
  { 0x645, 0x1EEAC },
156
  { 0x646, 0x1EEAD },
157
  { 0x648, 0x1EEA5 },
158
  { 0x64A, 0x1EEA9 }
159
};
160
161
static const MathVarMapping gLatinExceptionMapTable[] = {
162
  { 0x1D455, 0x210E },
163
  { 0x1D49D, 0x212C },
164
  { 0x1D4A0, 0x2130 },
165
  { 0x1D4A1, 0x2131 },
166
  { 0x1D4A3, 0x210B },
167
  { 0x1D4A4, 0x2110 },
168
  { 0x1D4A7, 0x2112 },
169
  { 0x1D4A8, 0x2133 },
170
  { 0x1D4AD, 0x211B },
171
  { 0x1D4BA, 0x212F },
172
  { 0x1D4BC, 0x210A },
173
  { 0x1D4C4, 0x2134 },
174
  { 0x1D506, 0x212D },
175
  { 0x1D50B, 0x210C },
176
  { 0x1D50C, 0x2111 },
177
  { 0x1D515, 0x211C },
178
  { 0x1D51D, 0x2128 },
179
  { 0x1D53A, 0x2102 },
180
  { 0x1D53F, 0x210D },
181
  { 0x1D545, 0x2115 },
182
  { 0x1D547, 0x2119 },
183
  { 0x1D548, 0x211A },
184
  { 0x1D549, 0x211D },
185
  { 0x1D551, 0x2124 }
186
};
187
188
// Finds a MathVarMapping struct with the specified key (aKey) within aTable.
189
// aTable must be an array, whose length is specified by aNumElements
190
static uint32_t
191
MathvarMappingSearch(uint32_t aKey, const MathVarMapping* aTable, uint32_t aNumElements)
192
{
193
  uint32_t low = 0;
194
  uint32_t high = aNumElements;
195
  while (high > low) {
196
    uint32_t midPoint = (low+high) >> 1;
197
    if (aKey == aTable[midPoint].mKey) {
198
      return aTable[midPoint].mReplacement;
199
    }
200
    if (aKey > aTable[midPoint].mKey) {
201
      low = midPoint + 1;
202
    } else {
203
      high = midPoint;
204
    }
205
  }
206
  return 0;
207
}
208
209
#define GREEK_UPPER_THETA               0x03F4
210
#define HOLE_GREEK_UPPER_THETA          0x03A2
211
#define NABLA                           0x2207
212
#define PARTIAL_DIFFERENTIAL            0x2202
213
#define GREEK_UPPER_ALPHA               0x0391
214
#define GREEK_UPPER_OMEGA               0x03A9
215
#define GREEK_LOWER_ALPHA               0x03B1
216
#define GREEK_LOWER_OMEGA               0x03C9
217
#define GREEK_LUNATE_EPSILON_SYMBOL     0x03F5
218
#define GREEK_THETA_SYMBOL              0x03D1
219
#define GREEK_KAPPA_SYMBOL              0x03F0
220
#define GREEK_PHI_SYMBOL                0x03D5
221
#define GREEK_RHO_SYMBOL                0x03F1
222
#define GREEK_PI_SYMBOL                 0x03D6
223
#define GREEK_LETTER_DIGAMMA            0x03DC
224
#define GREEK_SMALL_LETTER_DIGAMMA      0x03DD
225
#define MATH_BOLD_CAPITAL_DIGAMMA       0x1D7CA
226
#define MATH_BOLD_SMALL_DIGAMMA         0x1D7CB
227
228
#define LATIN_SMALL_LETTER_DOTLESS_I    0x0131
229
#define LATIN_SMALL_LETTER_DOTLESS_J    0x0237
230
231
#define MATH_ITALIC_SMALL_DOTLESS_I     0x1D6A4
232
#define MATH_ITALIC_SMALL_DOTLESS_J     0x1D6A5
233
234
#define MATH_BOLD_UPPER_A               0x1D400
235
#define MATH_ITALIC_UPPER_A             0x1D434
236
#define MATH_BOLD_SMALL_A               0x1D41A
237
#define MATH_BOLD_UPPER_ALPHA           0x1D6A8
238
#define MATH_BOLD_SMALL_ALPHA           0x1D6C2
239
#define MATH_ITALIC_UPPER_ALPHA         0x1D6E2
240
#define MATH_BOLD_DIGIT_ZERO            0x1D7CE
241
#define MATH_DOUBLE_STRUCK_ZERO         0x1D7D8
242
243
#define MATH_BOLD_UPPER_THETA           0x1D6B9
244
#define MATH_BOLD_NABLA                 0x1D6C1
245
#define MATH_BOLD_PARTIAL_DIFFERENTIAL  0x1D6DB
246
#define MATH_BOLD_EPSILON_SYMBOL        0x1D6DC
247
#define MATH_BOLD_THETA_SYMBOL          0x1D6DD
248
#define MATH_BOLD_KAPPA_SYMBOL          0x1D6DE
249
#define MATH_BOLD_PHI_SYMBOL            0x1D6DF
250
#define MATH_BOLD_RHO_SYMBOL            0x1D6E0
251
#define MATH_BOLD_PI_SYMBOL             0x1D6E1
252
253
/*
254
  Performs the character mapping needed to implement MathML's mathvariant
255
  attribute.  It takes a unicode character and maps it to its appropriate
256
  mathvariant counterpart specified by aMathVar.  The mapped character is
257
  typically located within Unicode's mathematical blocks (0x1D***, 0x1EE**) but
258
  there are exceptions which this function accounts for.
259
  Characters without a valid mapping or valid aMathvar value are returned
260
  unaltered.  Characters already in the mathematical blocks (or are one of the
261
  exceptions) are never transformed.
262
  Acceptable values for aMathVar are specified in layout/style/nsStyleConsts.h.
263
  The transformable characters can be found at:
264
  http://lists.w3.org/Archives/Public/www-math/2013Sep/0012.html and
265
  https://en.wikipedia.org/wiki/Mathematical_Alphanumeric_Symbols
266
*/
267
static uint32_t
268
MathVariant(uint32_t aCh, uint8_t aMathVar)
269
{
270
  uint32_t baseChar;
271
  enum CharacterType {
272
    kIsLatin,
273
    kIsGreekish,
274
    kIsNumber,
275
    kIsArabic,
276
  };
277
  CharacterType varType;
278
279
  int8_t multiplier;
280
281
  if (aMathVar <= NS_MATHML_MATHVARIANT_NORMAL) {
282
    // nothing to do here
283
    return aCh;
284
  }
285
  if (aMathVar > NS_MATHML_MATHVARIANT_STRETCHED) {
286
    NS_ASSERTION(false, "Illegal mathvariant value");
287
    return aCh;
288
  }
289
290
  // Exceptional characters with at most one possible transformation
291
  if (aCh == HOLE_GREEK_UPPER_THETA) {
292
    // Nothing at this code point is transformed
293
    return aCh;
294
  }
295
  if (aCh == GREEK_LETTER_DIGAMMA) {
296
    if (aMathVar == NS_MATHML_MATHVARIANT_BOLD)
297
      return MATH_BOLD_CAPITAL_DIGAMMA;
298
    else
299
      return aCh;
300
  }
301
  if (aCh == GREEK_SMALL_LETTER_DIGAMMA) {
302
    if (aMathVar == NS_MATHML_MATHVARIANT_BOLD)
303
      return MATH_BOLD_SMALL_DIGAMMA;
304
    else
305
      return aCh;
306
  }
307
  if (aCh == LATIN_SMALL_LETTER_DOTLESS_I) {
308
    if (aMathVar == NS_MATHML_MATHVARIANT_ITALIC)
309
      return MATH_ITALIC_SMALL_DOTLESS_I;
310
    else
311
      return aCh;
312
  }
313
  if (aCh == LATIN_SMALL_LETTER_DOTLESS_J) {
314
    if (aMathVar == NS_MATHML_MATHVARIANT_ITALIC)
315
      return MATH_ITALIC_SMALL_DOTLESS_J;
316
    else
317
      return aCh;
318
  }
319
320
  // The Unicode mathematical blocks are divided into four segments: Latin,
321
  // Greek, numbers and Arabic.  In the case of the first three
322
  // baseChar represents the relative order in which the characters are
323
  // encoded in the Unicode mathematical block, normalised to the first
324
  // character of that sequence.
325
  //
326
  if ('A' <= aCh && aCh <= 'Z') {
327
    baseChar = aCh - 'A';
328
    varType = kIsLatin;
329
  } else if ('a' <= aCh && aCh <= 'z') {
330
    // Lowercase characters are placed immediately after the uppercase
331
    // characters in the Unicode mathematical block.  The constant subtraction
332
    // represents the number of characters between the start of the sequence
333
    // (capital A) and the first lowercase letter.
334
    baseChar = MATH_BOLD_SMALL_A-MATH_BOLD_UPPER_A + aCh - 'a';
335
    varType = kIsLatin;
336
  } else if ('0' <= aCh && aCh <= '9') {
337
    baseChar = aCh - '0';
338
    varType = kIsNumber;
339
  } else if (GREEK_UPPER_ALPHA <= aCh && aCh <= GREEK_UPPER_OMEGA) {
340
    baseChar = aCh-GREEK_UPPER_ALPHA;
341
    varType = kIsGreekish;
342
  } else if (GREEK_LOWER_ALPHA <= aCh && aCh <= GREEK_LOWER_OMEGA) {
343
    // Lowercase Greek comes after uppercase Greek.
344
    // Note in this instance the presence of an additional character (Nabla)
345
    // between the end of the uppercase Greek characters and the lowercase
346
    // ones.
347
    baseChar =  MATH_BOLD_SMALL_ALPHA - MATH_BOLD_UPPER_ALPHA
348
                + aCh-GREEK_LOWER_ALPHA;
349
    varType = kIsGreekish;
350
  } else if (0x0600 <= aCh && aCh <= 0x06FF) {
351
    // Arabic characters are defined within this range
352
    varType = kIsArabic;
353
  } else {
354
    switch (aCh) {
355
      case GREEK_UPPER_THETA:
356
        baseChar = MATH_BOLD_UPPER_THETA-MATH_BOLD_UPPER_ALPHA;
357
        break;
358
      case NABLA:
359
        baseChar = MATH_BOLD_NABLA-MATH_BOLD_UPPER_ALPHA;
360
        break;
361
      case PARTIAL_DIFFERENTIAL:
362
        baseChar = MATH_BOLD_PARTIAL_DIFFERENTIAL - MATH_BOLD_UPPER_ALPHA;
363
        break;
364
      case GREEK_LUNATE_EPSILON_SYMBOL:
365
        baseChar = MATH_BOLD_EPSILON_SYMBOL - MATH_BOLD_UPPER_ALPHA;
366
        break;
367
      case GREEK_THETA_SYMBOL:
368
        baseChar = MATH_BOLD_THETA_SYMBOL - MATH_BOLD_UPPER_ALPHA;
369
        break;
370
      case GREEK_KAPPA_SYMBOL:
371
        baseChar = MATH_BOLD_KAPPA_SYMBOL - MATH_BOLD_UPPER_ALPHA;
372
        break;
373
      case GREEK_PHI_SYMBOL:
374
        baseChar = MATH_BOLD_PHI_SYMBOL - MATH_BOLD_UPPER_ALPHA;
375
        break;
376
      case GREEK_RHO_SYMBOL:
377
        baseChar = MATH_BOLD_RHO_SYMBOL - MATH_BOLD_UPPER_ALPHA;
378
        break;
379
      case GREEK_PI_SYMBOL:
380
        baseChar = MATH_BOLD_PI_SYMBOL - MATH_BOLD_UPPER_ALPHA;
381
        break;
382
      default:
383
        return aCh;
384
    }
385
386
    varType = kIsGreekish;
387
  }
388
389
  if (varType == kIsNumber) {
390
    switch (aMathVar) {
391
      // Each possible number mathvariant is encoded in a single, contiguous
392
      // block.  For example the beginning of the double struck number range
393
      // follows immediately after the end of the bold number range.
394
      // multiplier represents the order of the sequences relative to the first
395
      // one.
396
      case NS_MATHML_MATHVARIANT_BOLD:
397
        multiplier = 0;
398
        break;
399
      case NS_MATHML_MATHVARIANT_DOUBLE_STRUCK:
400
        multiplier = 1;
401
        break;
402
      case NS_MATHML_MATHVARIANT_SANS_SERIF:
403
        multiplier = 2;
404
        break;
405
      case NS_MATHML_MATHVARIANT_BOLD_SANS_SERIF:
406
        multiplier = 3;
407
        break;
408
      case NS_MATHML_MATHVARIANT_MONOSPACE:
409
        multiplier = 4;
410
        break;
411
      default:
412
        // This mathvariant isn't defined for numbers or is otherwise normal
413
        return aCh;
414
    }
415
    // As the ranges are contiguous, to find the desired mathvariant range it
416
    // is sufficient to multiply the position within the sequence order
417
    // (multiplier) with the period of the sequence (which is constant for all
418
    // number sequences) and to add the character point of the first character
419
    // within the number mathvariant range.
420
    // To this the baseChar calculated earlier is added to obtain the final
421
    // code point.
422
    return baseChar+multiplier*(MATH_DOUBLE_STRUCK_ZERO-MATH_BOLD_DIGIT_ZERO)
423
             +MATH_BOLD_DIGIT_ZERO;
424
  } else if (varType == kIsGreekish) {
425
    switch (aMathVar) {
426
      case NS_MATHML_MATHVARIANT_BOLD:
427
        multiplier = 0;
428
        break;
429
      case NS_MATHML_MATHVARIANT_ITALIC:
430
        multiplier = 1;
431
        break;
432
      case NS_MATHML_MATHVARIANT_BOLD_ITALIC:
433
        multiplier = 2;
434
        break;
435
      case NS_MATHML_MATHVARIANT_BOLD_SANS_SERIF:
436
        multiplier = 3;
437
        break;
438
      case NS_MATHML_MATHVARIANT_SANS_SERIF_BOLD_ITALIC:
439
        multiplier = 4;
440
        break;
441
      default:
442
        // This mathvariant isn't defined for Greek or is otherwise normal
443
        return aCh;
444
    }
445
    // See the kIsNumber case for an explanation of the following calculation
446
    return baseChar + MATH_BOLD_UPPER_ALPHA +
447
             multiplier*(MATH_ITALIC_UPPER_ALPHA - MATH_BOLD_UPPER_ALPHA);
448
  }
449
450
  uint32_t tempChar;
451
  uint32_t newChar;
452
  if (varType == kIsArabic) {
453
    const MathVarMapping* mapTable;
454
    uint32_t tableLength;
455
    switch (aMathVar) {
456
      /* The Arabic mathematical block is not continuous, nor does it have a
457
       * monotonic mapping to the unencoded characters, requiring the use of a
458
       * lookup table.
459
       */
460
      case NS_MATHML_MATHVARIANT_INITIAL:
461
        mapTable = gArabicInitialMapTable;
462
        tableLength = ArrayLength(gArabicInitialMapTable);
463
        break;
464
      case NS_MATHML_MATHVARIANT_TAILED:
465
        mapTable = gArabicTailedMapTable;
466
        tableLength = ArrayLength(gArabicTailedMapTable);
467
        break;
468
      case NS_MATHML_MATHVARIANT_STRETCHED:
469
        mapTable = gArabicStretchedMapTable;
470
        tableLength = ArrayLength(gArabicStretchedMapTable);
471
        break;
472
      case NS_MATHML_MATHVARIANT_LOOPED:
473
        mapTable = gArabicLoopedMapTable;
474
        tableLength = ArrayLength(gArabicLoopedMapTable);
475
        break;
476
      case NS_MATHML_MATHVARIANT_DOUBLE_STRUCK:
477
        mapTable = gArabicDoubleMapTable;
478
        tableLength = ArrayLength(gArabicDoubleMapTable);
479
        break;
480
      default:
481
        // No valid transformations exist
482
        return aCh;
483
    }
484
    newChar = MathvarMappingSearch(aCh, mapTable, tableLength);
485
  } else {
486
    // Must be Latin
487
    if (aMathVar > NS_MATHML_MATHVARIANT_MONOSPACE) {
488
      // Latin doesn't support the Arabic mathvariants
489
      return aCh;
490
    }
491
    multiplier = aMathVar - 2;
492
    // This is possible because the values for NS_MATHML_MATHVARIANT_* are
493
    // chosen to coincide with the order in which the encoded mathvariant
494
    // characters are located within their unicode block (less an offset to
495
    // avoid _NONE and _NORMAL variants)
496
    // See the kIsNumber case for an explanation of the following calculation
497
    tempChar =  baseChar + MATH_BOLD_UPPER_A +
498
                multiplier*(MATH_ITALIC_UPPER_A - MATH_BOLD_UPPER_A);
499
    // There are roughly twenty characters that are located outside of the
500
    // mathematical block, so the spaces where they ought to be are used
501
    // as keys for a lookup table containing the correct character mappings.
502
    newChar = MathvarMappingSearch(tempChar, gLatinExceptionMapTable,
503
                                   ArrayLength(gLatinExceptionMapTable));
504
  }
505
506
  if (newChar) {
507
    return newChar;
508
  } else if (varType == kIsLatin) {
509
    return tempChar;
510
  } else {
511
    // An Arabic character without a corresponding mapping
512
    return aCh;
513
  }
514
515
}
516
517
void
518
nsMathVariantTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
519
                                            gfxContext* aRefContext)
520
{
521
  gfxFontGroup* fontGroup = aTextRun->GetFontGroup();
522
  gfxFontStyle fontStyle = *fontGroup->GetStyle();
523
524
  nsAutoString convertedString;
525
  nsAutoTArray<bool,50> charsToMergeArray;
526
  nsAutoTArray<bool,50> deletedCharsArray;
527
  nsAutoTArray<nsStyleContext*,50> styleArray;
528
  nsAutoTArray<uint8_t,50> canBreakBeforeArray;
529
  bool mergeNeeded = false;
530
531
  bool singleCharMI =
532
    aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SINGLE_CHAR_MI;
533
534
  uint32_t length = aTextRun->GetLength();
535
  const PRUnichar* str = aTextRun->mString.BeginReading();
536
  nsRefPtr<nsStyleContext>* styles = aTextRun->mStyles.Elements();
537
538
  uint8_t mathVar;
539
  bool doMathvariantStyling = true;
540
541
  for (uint32_t i = 0; i < length; ++i) {
542
    int extraChars = 0;
543
    nsStyleContext* styleContext = styles[i];
544
    mathVar = styleContext->StyleFont()->mMathVariant;
545
546
    if (singleCharMI && mathVar == NS_MATHML_MATHVARIANT_NONE) {
547
      mathVar = NS_MATHML_MATHVARIANT_ITALIC;
548
    }
549
550
    uint32_t ch = str[i];
551
    if (NS_IS_HIGH_SURROGATE(ch) && i < length - 1 &&
552
        NS_IS_LOW_SURROGATE(str[i + 1])) {
553
      ch = SURROGATE_TO_UCS4(ch, str[i + 1]);
554
    }
555
    uint32_t ch2 = MathVariant(ch, mathVar);
556
557
    if (mathVar == NS_MATHML_MATHVARIANT_BOLD ||
558
        mathVar == NS_MATHML_MATHVARIANT_BOLD_ITALIC ||
559
        mathVar == NS_MATHML_MATHVARIANT_ITALIC) {
560
      if (ch == ch2  && ch != 0x20 && ch != 0xA0) {
561
        // Don't perform the transformation if a character cannot be
562
        // transformed. There is an exception for whitespace as it is both
563
        // common and innocuous.
564
        doMathvariantStyling = false;
565
      }
566
      // Undo the change as it will be handled as a font styling.
567
      ch2 = ch;
568
    }
569
570
    deletedCharsArray.AppendElement(false);
571
    charsToMergeArray.AppendElement(false);
572
    styleArray.AppendElement(styleContext);
573
    canBreakBeforeArray.AppendElement(aTextRun->CanBreakLineBefore(i));
574
575
    if (IS_IN_BMP(ch2)) {
576
      convertedString.Append(ch2);
577
    } else {
578
      convertedString.Append(H_SURROGATE(ch2));
579
      convertedString.Append(L_SURROGATE(ch2));
580
      ++extraChars;
581
      if (!IS_IN_BMP(ch)) {
582
        deletedCharsArray.AppendElement(true); // not exactly deleted, but
583
                                          // the trailing surrogate is skipped
584
        ++i;
585
      }
586
    }
587
588
    while (extraChars-- > 0) {
589
      mergeNeeded = true;
590
      charsToMergeArray.AppendElement(true);
591
      styleArray.AppendElement(styleContext);
592
      canBreakBeforeArray.AppendElement(false);
593
    }
594
  }
595
596
  uint32_t flags;
597
  gfxTextRunFactory::Parameters innerParams =
598
      GetParametersForInner(aTextRun, &flags, aRefContext);
599
600
  nsAutoPtr<nsTransformedTextRun> transformedChild;
601
  nsAutoPtr<gfxTextRun> cachedChild;
602
  gfxTextRun* child;
603
604
  if (mathVar == NS_MATHML_MATHVARIANT_BOLD && doMathvariantStyling) {
605
    fontStyle.style = NS_FONT_STYLE_NORMAL;
606
    fontStyle.weight = NS_FONT_WEIGHT_BOLD;
607
  } else if (mathVar == NS_MATHML_MATHVARIANT_ITALIC && doMathvariantStyling) {
608
    fontStyle.style = NS_FONT_STYLE_ITALIC;
609
    fontStyle.weight = NS_FONT_WEIGHT_NORMAL;
610
  } else if (mathVar == NS_MATHML_MATHVARIANT_BOLD_ITALIC &&
611
             doMathvariantStyling) {
612
    fontStyle.style = NS_FONT_STYLE_ITALIC;
613
    fontStyle.weight = NS_FONT_WEIGHT_BOLD;
614
  } else {
615
    // Mathvariant overrides fontstyle and fontweight
616
    fontStyle.style = NS_FONT_STYLE_NORMAL;
617
    fontStyle.weight = NS_FONT_WEIGHT_NORMAL;
618
  }
619
  nsRefPtr<gfxFontGroup> newFontGroup = fontGroup->Copy(&fontStyle);
620
621
  if (!newFontGroup)
622
    return;
623
624
  if (mInnerTransformingTextRunFactory) {
625
    transformedChild = mInnerTransformingTextRunFactory->MakeTextRun(
626
        convertedString.BeginReading(), convertedString.Length(),
627
        &innerParams, newFontGroup, flags, styleArray.Elements(), false);
628
    child = transformedChild.get();
629
  } else {
630
    cachedChild = newFontGroup->MakeTextRun(
631
        convertedString.BeginReading(), convertedString.Length(),
632
        &innerParams, flags);
633
    child = cachedChild.get();
634
  }
635
  if (!child)
636
    return;
637
  // Copy potential linebreaks into child so they're preserved
638
  // (and also child will be shaped appropriately)
639
  NS_ASSERTION(convertedString.Length() == canBreakBeforeArray.Length(),
640
               "Dropped characters or break-before values somewhere!");
641
  child->SetPotentialLineBreaks(0, canBreakBeforeArray.Length(),
642
      canBreakBeforeArray.Elements(), aRefContext);
643
  if (transformedChild) {
644
    transformedChild->FinishSettingProperties(aRefContext);
645
  }
646
647
  if (mergeNeeded) {
648
    // Now merge multiple characters into one multi-glyph character as required
649
    NS_ASSERTION(charsToMergeArray.Length() == child->GetLength(),
650
                 "source length mismatch");
651
    NS_ASSERTION(deletedCharsArray.Length() == aTextRun->GetLength(),
652
                 "destination length mismatch");
653
    MergeCharactersInTextRun(aTextRun, child, charsToMergeArray.Elements(),
654
                             deletedCharsArray.Elements());
655
  } else {
656
    // No merging to do, so just copy; this produces a more optimized textrun.
657
    // We can't steal the data because the child may be cached and stealing
658
    // the data would break the cache.
659
    aTextRun->ResetGlyphRuns();
660
    aTextRun->CopyGlyphDataFrom(child, 0, child->GetLength(), 0);
661
  }
662
}
(-)a/layout/generic/MathVariantTextRunFactory.h (+25 lines)
Line     Link Here 
Line 0    Link Here 
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2
 * This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#ifndef MATHVARIANTTEXTRUNFACTORY_H_
7
#define MATHVARIANTTEXTRUNFACTORY_H_
8
9
#include "nsTextRunTransformations.h"
10
11
/**
12
 * Builds textruns that render their text using a mathvariant
13
 */
14
class nsMathVariantTextRunFactory : public nsTransformingTextRunFactory {
15
public:
16
  nsMathVariantTextRunFactory(nsTransformingTextRunFactory* aInnerTransformingTextRunFactory)
17
    : mInnerTransformingTextRunFactory(aInnerTransformingTextRunFactory) {}
18
19
  virtual void RebuildTextRun(nsTransformedTextRun* aTextRun,
20
                              gfxContext* aRefContext) MOZ_OVERRIDE;
21
protected:
22
  nsAutoPtr<nsTransformingTextRunFactory> mInnerTransformingTextRunFactory;
23
};
24
25
#endif /*MATHVARIANTTEXTRUNFACTORY_H_*/
(-)a/layout/generic/moz.build (+1 lines)
Line     Link Here 
 Lines 38-53   EXPORTS.mozilla += [ Link Here 
38
]
38
]
39
39
40
EXPORTS.mozilla.layout += [
40
EXPORTS.mozilla.layout += [
41
    'FrameChildList.h',
41
    'FrameChildList.h',
42
]
42
]
43
43
44
UNIFIED_SOURCES += [
44
UNIFIED_SOURCES += [
45
    'FrameChildList.cpp',
45
    'FrameChildList.cpp',
46
    'MathVariantTextRunFactory.cpp',
46
    'nsAbsoluteContainingBlock.cpp',
47
    'nsAbsoluteContainingBlock.cpp',
47
    'nsBlockFrame.cpp',
48
    'nsBlockFrame.cpp',
48
    'nsBlockReflowContext.cpp',
49
    'nsBlockReflowContext.cpp',
49
    'nsBlockReflowState.cpp',
50
    'nsBlockReflowState.cpp',
50
    'nsBRFrame.cpp',
51
    'nsBRFrame.cpp',
51
    'nsBulletFrame.cpp',
52
    'nsBulletFrame.cpp',
52
    'nsCanvasFrame.cpp',
53
    'nsCanvasFrame.cpp',
53
    'nsColumnSetFrame.cpp',
54
    'nsColumnSetFrame.cpp',
(-)a/layout/generic/nsTextFrame.cpp (+19 lines)
Line     Link Here 
 Lines 36-51    Link Here 
36
#include "nsCompatibility.h"
36
#include "nsCompatibility.h"
37
#include "nsCSSColorUtils.h"
37
#include "nsCSSColorUtils.h"
38
#include "nsLayoutUtils.h"
38
#include "nsLayoutUtils.h"
39
#include "nsDisplayList.h"
39
#include "nsDisplayList.h"
40
#include "nsFrame.h"
40
#include "nsFrame.h"
41
#include "nsPlaceholderFrame.h"
41
#include "nsPlaceholderFrame.h"
42
#include "nsTextFrameUtils.h"
42
#include "nsTextFrameUtils.h"
43
#include "nsTextRunTransformations.h"
43
#include "nsTextRunTransformations.h"
44
#include "MathVariantTextRunFactory.h"
44
#include "nsExpirationTracker.h"
45
#include "nsExpirationTracker.h"
45
#include "nsUnicodeProperties.h"
46
#include "nsUnicodeProperties.h"
46
47
47
#include "nsTextFragment.h"
48
#include "nsTextFragment.h"
48
#include "nsGkAtoms.h"
49
#include "nsGkAtoms.h"
49
#include "nsFrameSelection.h"
50
#include "nsFrameSelection.h"
50
#include "nsRange.h"
51
#include "nsRange.h"
51
#include "nsCSSRendering.h"
52
#include "nsCSSRendering.h"
 Lines 216-231   NS_DECLARE_FRAME_PROPERTY(TextFrameGlyph Link Here 
216
#define TEXT_IN_TEXTRUN_USER_DATA  NS_FRAME_STATE_BIT(29)
217
#define TEXT_IN_TEXTRUN_USER_DATA  NS_FRAME_STATE_BIT(29)
217
218
218
// nsTextFrame.h has
219
// nsTextFrame.h has
219
// #define TEXT_HAS_NONCOLLAPSED_CHARACTERS NS_FRAME_STATE_BIT(31)
220
// #define TEXT_HAS_NONCOLLAPSED_CHARACTERS NS_FRAME_STATE_BIT(31)
220
221
221
// nsTextFrame.h has
222
// nsTextFrame.h has
222
// #define TEXT_IS_IN_TOKEN_MATHML          NS_FRAME_STATE_BIT(32)
223
// #define TEXT_IS_IN_TOKEN_MATHML          NS_FRAME_STATE_BIT(32)
223
224
225
// nsTextFrame.h has
226
// #define TEXT_IS_IN_SINGLE_CHAR_MI        NS_FRAME_STATE_BIT(59)
227
224
// Set when this text frame is mentioned in the userdata for the
228
// Set when this text frame is mentioned in the userdata for the
225
// uninflated textrun property
229
// uninflated textrun property
226
#define TEXT_IN_UNINFLATED_TEXTRUN_USER_DATA NS_FRAME_STATE_BIT(60)
230
#define TEXT_IN_UNINFLATED_TEXTRUN_USER_DATA NS_FRAME_STATE_BIT(60)
227
231
228
// nsTextFrame.h has
232
// nsTextFrame.h has
229
// #define TEXT_HAS_FONT_INFLATION          NS_FRAME_STATE_BIT(61)
233
// #define TEXT_HAS_FONT_INFLATION          NS_FRAME_STATE_BIT(61)
230
234
231
// If true, then this frame is being removed due to a SetLength() on a
235
// If true, then this frame is being removed due to a SetLength() on a
 Lines 1291-1306   BuildTextRuns(gfxContext* aContext, nsTe Link Here 
1291
  } else {
1295
  } else {
1292
    NS_ASSERTION(!aForFrame ||
1296
    NS_ASSERTION(!aForFrame ||
1293
                 (aLineContainer == FindLineContainer(aForFrame) ||
1297
                 (aLineContainer == FindLineContainer(aForFrame) ||
1294
                  (aLineContainer->GetType() == nsGkAtoms::letterFrame &&
1298
                  (aLineContainer->GetType() == nsGkAtoms::letterFrame &&
1295
                   aLineContainer->IsFloating())),
1299
                   aLineContainer->IsFloating())),
1296
                 "Wrong line container hint");
1300
                 "Wrong line container hint");
1297
  }
1301
  }
1298
1302
1303
  if (aForFrame && aForFrame->HasAnyStateBits(TEXT_IS_IN_SINGLE_CHAR_MI)) {
1304
    aLineContainer->AddStateBits(TEXT_IS_IN_SINGLE_CHAR_MI);
1305
  }
1306
1299
  nsPresContext* presContext = aLineContainer->PresContext();
1307
  nsPresContext* presContext = aLineContainer->PresContext();
1300
  BuildTextRunsScanner scanner(presContext, aContext, aLineContainer,
1308
  BuildTextRunsScanner scanner(presContext, aContext, aLineContainer,
1301
                               aWhichTextRun);
1309
                               aWhichTextRun);
1302
1310
1303
  nsBlockFrame* block = nsLayoutUtils::GetAsBlock(aLineContainer);
1311
  nsBlockFrame* block = nsLayoutUtils::GetAsBlock(aLineContainer);
1304
1312
1305
  if (!block) {
1313
  if (!block) {
1306
    NS_ASSERTION(!aLineContainer->GetPrevInFlow() && !aLineContainer->GetNextInFlow(),
1314
    NS_ASSERTION(!aLineContainer->GetPrevInFlow() && !aLineContainer->GetNextInFlow(),
 Lines 1854-1869   static const nsTextFrameUtils::Compressi Link Here 
1854
gfxTextRun*
1862
gfxTextRun*
1855
BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
1863
BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
1856
{
1864
{
1857
  gfxSkipCharsBuilder builder;
1865
  gfxSkipCharsBuilder builder;
1858
1866
1859
  const void* textPtr = aTextBuffer;
1867
  const void* textPtr = aTextBuffer;
1860
  bool anySmallcapsStyle = false;
1868
  bool anySmallcapsStyle = false;
1861
  bool anyTextTransformStyle = false;
1869
  bool anyTextTransformStyle = false;
1870
  bool anyMathVariantStyle = false;
1862
  uint32_t textFlags = nsTextFrameUtils::TEXT_NO_BREAKS;
1871
  uint32_t textFlags = nsTextFrameUtils::TEXT_NO_BREAKS;
1863
1872
1864
  if (mCurrentRunContextInfo & nsTextFrameUtils::INCOMING_WHITESPACE) {
1873
  if (mCurrentRunContextInfo & nsTextFrameUtils::INCOMING_WHITESPACE) {
1865
    textFlags |= nsTextFrameUtils::TEXT_INCOMING_WHITESPACE;
1874
    textFlags |= nsTextFrameUtils::TEXT_INCOMING_WHITESPACE;
1866
  }
1875
  }
1867
  if (mCurrentRunContextInfo & nsTextFrameUtils::INCOMING_ARABICCHAR) {
1876
  if (mCurrentRunContextInfo & nsTextFrameUtils::INCOMING_ARABICCHAR) {
1868
    textFlags |= gfxTextRunFactory::TEXT_INCOMING_ARABICCHAR;
1877
    textFlags |= gfxTextRunFactory::TEXT_INCOMING_ARABICCHAR;
1869
  }
1878
  }
 Lines 1931-1946   BuildTextRunsScanner::BuildTextRunForFra Link Here 
1931
      CSSWhitespaceToCompressionMode[textStyle->mWhiteSpace];
1940
      CSSWhitespaceToCompressionMode[textStyle->mWhiteSpace];
1932
    if (enabledJustification && !textStyle->WhiteSpaceIsSignificant()) {
1941
    if (enabledJustification && !textStyle->WhiteSpaceIsSignificant()) {
1933
      textFlags |= gfxTextRunFactory::TEXT_ENABLE_SPACING;
1942
      textFlags |= gfxTextRunFactory::TEXT_ENABLE_SPACING;
1934
    }
1943
    }
1935
    fontStyle = f->StyleFont();
1944
    fontStyle = f->StyleFont();
1936
    if (NS_STYLE_FONT_VARIANT_SMALL_CAPS == fontStyle->mFont.variant) {
1945
    if (NS_STYLE_FONT_VARIANT_SMALL_CAPS == fontStyle->mFont.variant) {
1937
      anySmallcapsStyle = true;
1946
      anySmallcapsStyle = true;
1938
    }
1947
    }
1948
    if (NS_MATHML_MATHVARIANT_NONE != fontStyle->mMathVariant) {
1949
      anyMathVariantStyle = true;
1950
    } else if (mLineContainer->GetStateBits() & TEXT_IS_IN_SINGLE_CHAR_MI) {
1951
      textFlags |= nsTextFrameUtils::TEXT_IS_SINGLE_CHAR_MI;
1952
      anyMathVariantStyle = true;
1953
    }
1939
1954
1940
    // Figure out what content is included in this flow.
1955
    // Figure out what content is included in this flow.
1941
    nsIContent* content = f->GetContent();
1956
    nsIContent* content = f->GetContent();
1942
    const nsTextFragment* frag = content->GetText();
1957
    const nsTextFragment* frag = content->GetText();
1943
    int32_t contentStart = mappedFlow->mStartFrame->GetContentOffset();
1958
    int32_t contentStart = mappedFlow->mStartFrame->GetContentOffset();
1944
    int32_t contentEnd = mappedFlow->GetContentEnd();
1959
    int32_t contentEnd = mappedFlow->GetContentEnd();
1945
    int32_t contentLength = contentEnd - contentStart;
1960
    int32_t contentLength = contentEnd - contentStart;
1946
1961
 Lines 2072-2087   BuildTextRunsScanner::BuildTextRunForFra Link Here 
2072
  nsAutoPtr<nsTransformingTextRunFactory> transformingFactory;
2087
  nsAutoPtr<nsTransformingTextRunFactory> transformingFactory;
2073
  if (anySmallcapsStyle) {
2088
  if (anySmallcapsStyle) {
2074
    transformingFactory = new nsFontVariantTextRunFactory();
2089
    transformingFactory = new nsFontVariantTextRunFactory();
2075
  }
2090
  }
2076
  if (anyTextTransformStyle) {
2091
  if (anyTextTransformStyle) {
2077
    transformingFactory =
2092
    transformingFactory =
2078
      new nsCaseTransformTextRunFactory(transformingFactory.forget());
2093
      new nsCaseTransformTextRunFactory(transformingFactory.forget());
2079
  }
2094
  }
2095
  if (anyMathVariantStyle) {
2096
    transformingFactory =
2097
      new nsMathVariantTextRunFactory(transformingFactory.forget());
2098
  }
2080
  nsTArray<nsStyleContext*> styles;
2099
  nsTArray<nsStyleContext*> styles;
2081
  if (transformingFactory) {
2100
  if (transformingFactory) {
2082
    iter.SetOriginalOffset(0);
2101
    iter.SetOriginalOffset(0);
2083
    for (uint32_t i = 0; i < mMappedFlows.Length(); ++i) {
2102
    for (uint32_t i = 0; i < mMappedFlows.Length(); ++i) {
2084
      MappedFlow* mappedFlow = &mMappedFlows[i];
2103
      MappedFlow* mappedFlow = &mMappedFlows[i];
2085
      nsTextFrame* f;
2104
      nsTextFrame* f;
2086
      for (f = mappedFlow->mStartFrame; f != mappedFlow->mEndFrame;
2105
      for (f = mappedFlow->mStartFrame; f != mappedFlow->mEndFrame;
2087
           f = static_cast<nsTextFrame*>(f->GetNextContinuation())) {
2106
           f = static_cast<nsTextFrame*>(f->GetNextContinuation())) {
(-)a/layout/generic/nsTextFrame.h (+5 lines)
Line     Link Here 
 Lines 19-34   class PropertyProvider; Link Here 
19
19
20
// This state bit is set on frames that have some non-collapsed characters after
20
// This state bit is set on frames that have some non-collapsed characters after
21
// reflow
21
// reflow
22
#define TEXT_HAS_NONCOLLAPSED_CHARACTERS NS_FRAME_STATE_BIT(31)
22
#define TEXT_HAS_NONCOLLAPSED_CHARACTERS NS_FRAME_STATE_BIT(31)
23
23
24
// This state bit is set on children of token MathML elements
24
// This state bit is set on children of token MathML elements
25
#define TEXT_IS_IN_TOKEN_MATHML          NS_FRAME_STATE_BIT(32)
25
#define TEXT_IS_IN_TOKEN_MATHML          NS_FRAME_STATE_BIT(32)
26
26
27
// This state bit is set on token MathML elements if the token represents an
28
// <mi> tag whose inner HTML consists of a single non-whitespace character
29
// to allow special rendering behaviour.
30
#define TEXT_IS_IN_SINGLE_CHAR_MI        NS_FRAME_STATE_BIT(59)
31
27
#define TEXT_HAS_FONT_INFLATION          NS_FRAME_STATE_BIT(61)
32
#define TEXT_HAS_FONT_INFLATION          NS_FRAME_STATE_BIT(61)
28
33
29
typedef nsFrame nsTextFrameBase;
34
typedef nsFrame nsTextFrameBase;
30
35
31
class nsDisplayTextGeometry;
36
class nsDisplayTextGeometry;
32
class nsDisplayText;
37
class nsDisplayText;
33
38
34
class nsTextFrameTextRunCache {
39
class nsTextFrameTextRunCache {
(-)a/layout/generic/nsTextFrameUtils.h (-1 / +7 lines)
Line     Link Here 
 Lines 37-53   public: Link Here 
37
    TEXT_TRAILING_WHITESPACE = 0x400000,
37
    TEXT_TRAILING_WHITESPACE = 0x400000,
38
    TEXT_COMPRESSED_LEADING_WHITESPACE = 0x800000,
38
    TEXT_COMPRESSED_LEADING_WHITESPACE = 0x800000,
39
    TEXT_NO_BREAKS           = 0x1000000,
39
    TEXT_NO_BREAKS           = 0x1000000,
40
    TEXT_IS_TRANSFORMED      = 0x2000000,
40
    TEXT_IS_TRANSFORMED      = 0x2000000,
41
    // This gets set if there's a break opportunity at the end of the textrun.
41
    // This gets set if there's a break opportunity at the end of the textrun.
42
    // We normally don't use this break opportunity because the following text
42
    // We normally don't use this break opportunity because the following text
43
    // will have a break opportunity at the start, but it's useful for line
43
    // will have a break opportunity at the start, but it's useful for line
44
    // layout to know about it in case the following content is not text
44
    // layout to know about it in case the following content is not text
45
    TEXT_HAS_TRAILING_BREAK  = 0x4000000
45
    TEXT_HAS_TRAILING_BREAK  = 0x4000000,
46
47
    // This is set if the textrun was created for a textframe whose
48
    // TEXT_IS_IN_SINGLE_CHAR_MI flag is set.  This occurs if the textframe
49
    // belongs to a MathML <mi> element whose embedded text consists of a
50
    // single character.
51
    TEXT_IS_SINGLE_CHAR_MI   = 0x8000000
46
52
47
    // The following are defined by gfxTextRunWordCache rather than here,
53
    // The following are defined by gfxTextRunWordCache rather than here,
48
    // so that it also has access to the _INCOMING flag
54
    // so that it also has access to the _INCOMING flag
49
    // TEXT_TRAILING_ARABICCHAR
55
    // TEXT_TRAILING_ARABICCHAR
50
    // TEXT_INCOMING_ARABICCHAR
56
    // TEXT_INCOMING_ARABICCHAR
51
  };
57
  };
52
58
53
  // These constants are used in TransformText to represent context information
59
  // These constants are used in TransformText to represent context information
(-)a/layout/generic/nsTextRunTransformations.cpp (-32 / +5 lines)
Line     Link Here 
 Lines 8-23    Link Here 
8
#include "mozilla/MemoryReporting.h"
8
#include "mozilla/MemoryReporting.h"
9
9
10
#include "nsGkAtoms.h"
10
#include "nsGkAtoms.h"
11
#include "nsStyleConsts.h"
11
#include "nsStyleConsts.h"
12
#include "nsStyleContext.h"
12
#include "nsStyleContext.h"
13
#include "nsUnicodeProperties.h"
13
#include "nsUnicodeProperties.h"
14
#include "nsSpecialCasingData.h"
14
#include "nsSpecialCasingData.h"
15
#include "mozilla/gfx/2D.h"
15
#include "mozilla/gfx/2D.h"
16
#include "nsTextFrameUtils.h"
17
#include "nsIPersistentProperties2.h"
18
#include "nsNetUtil.h"
16
19
17
// Unicode characters needing special casing treatment in tr/az languages
20
// Unicode characters needing special casing treatment in tr/az languages
18
#define LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE  0x0130
21
#define LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE  0x0130
19
#define LATIN_SMALL_LETTER_DOTLESS_I           0x0131
22
#define LATIN_SMALL_LETTER_DOTLESS_I           0x0131
20
23
21
// Greek sigma needs custom handling for the lowercase transform; for details
24
// Greek sigma needs custom handling for the lowercase transform; for details
22
// see comments under "case NS_STYLE_TEXT_TRANSFORM_LOWERCASE" within
25
// see comments under "case NS_STYLE_TEXT_TRANSFORM_LOWERCASE" within
23
// nsCaseTransformTextRunFactory::RebuildTextRun(), and bug 740120.
26
// nsCaseTransformTextRunFactory::RebuildTextRun(), and bug 740120.
 Lines 392-438   nsTransformingTextRunFactory::MakeTextRu Link Here 
392
  // We'll only have a Unicode code path to minimize the amount of code needed
395
  // We'll only have a Unicode code path to minimize the amount of code needed
393
  // for these rarely used features
396
  // for these rarely used features
394
  NS_ConvertASCIItoUTF16 unicodeString(reinterpret_cast<const char*>(aString), aLength);
397
  NS_ConvertASCIItoUTF16 unicodeString(reinterpret_cast<const char*>(aString), aLength);
395
  return MakeTextRun(unicodeString.get(), aLength, aParams, aFontGroup,
398
  return MakeTextRun(unicodeString.get(), aLength, aParams, aFontGroup,
396
                     aFlags & ~(gfxFontGroup::TEXT_IS_PERSISTENT | gfxFontGroup::TEXT_IS_8BIT),
399
                     aFlags & ~(gfxFontGroup::TEXT_IS_PERSISTENT | gfxFontGroup::TEXT_IS_8BIT),
397
                     aStyles, aOwnsFactory);
400
                     aStyles, aOwnsFactory);
398
}
401
}
399
402
400
/**
403
void
401
 * Copy a given textrun, but merge certain characters into a single logical
402
 * character. Glyphs for a character are added to the glyph list for the previous
403
 * character and then the merged character is eliminated. Visually the results
404
 * are identical.
405
 * 
406
 * This is used for text-transform:uppercase when we encounter a SZLIG,
407
 * whose uppercase form is "SS", or other ligature or precomposed form
408
 * that expands to multiple codepoints during case transformation,
409
 * and for Greek text when combining diacritics have been deleted.
410
 * 
411
 * This function is unable to merge characters when they occur in different
412
 * glyph runs. This only happens in tricky edge cases where a character was
413
 * decomposed by case-mapping (e.g. there's no precomposed uppercase version
414
 * of an accented lowercase letter), and then font-matching caused the
415
 * diacritics to be assigned to a different font than the base character.
416
 * In this situation, the diacritic(s) get discarded, which is less than
417
 * ideal, but they probably weren't going to render very well anyway.
418
 * Bug 543200 will improve this by making font-matching operate on entire
419
 * clusters instead of individual codepoints.
420
 * 
421
 * For simplicity, this produces a textrun containing all DetailedGlyphs,
422
 * no simple glyphs. So don't call it unless you really have merging to do.
423
 * 
424
 * @param aCharsToMerge when aCharsToMerge[i] is true, this character in aSrc
425
 * is merged into the previous character
426
 *
427
 * @param aDeletedChars when aDeletedChars[i] is true, the character at this
428
 * position in aDest was deleted (has no corresponding char in aSrc)
429
 */
430
static void
431
MergeCharactersInTextRun(gfxTextRun* aDest, gfxTextRun* aSrc,
404
MergeCharactersInTextRun(gfxTextRun* aDest, gfxTextRun* aSrc,
432
                         const bool* aCharsToMerge, const bool* aDeletedChars)
405
                         const bool* aCharsToMerge, const bool* aDeletedChars)
433
{
406
{
434
  aDest->ResetGlyphRuns();
407
  aDest->ResetGlyphRuns();
435
408
436
  gfxTextRun::GlyphRunIterator iter(aSrc, 0, aSrc->GetLength());
409
  gfxTextRun::GlyphRunIterator iter(aSrc, 0, aSrc->GetLength());
437
  uint32_t offset = 0;
410
  uint32_t offset = 0;
438
  nsAutoTArray<gfxTextRun::DetailedGlyph,2> glyphs;
411
  nsAutoTArray<gfxTextRun::DetailedGlyph,2> glyphs;
 Lines 508-524   MergeCharactersInTextRun(gfxTextRun* aDe Link Here 
508
      }
481
      }
509
    }
482
    }
510
    NS_ASSERTION(glyphs.Length() == 0,
483
    NS_ASSERTION(glyphs.Length() == 0,
511
                 "Leftover glyphs, don't request merging of the last character with its next!");  
484
                 "Leftover glyphs, don't request merging of the last character with its next!");  
512
  }
485
  }
513
  NS_ASSERTION(offset == aDest->GetLength(), "Bad offset calculations");
486
  NS_ASSERTION(offset == aDest->GetLength(), "Bad offset calculations");
514
}
487
}
515
488
516
static gfxTextRunFactory::Parameters
489
gfxTextRunFactory::Parameters
517
GetParametersForInner(nsTransformedTextRun* aTextRun, uint32_t* aFlags,
490
GetParametersForInner(nsTransformedTextRun* aTextRun, uint32_t* aFlags,
518
    gfxContext* aRefContext)
491
    gfxContext* aRefContext)
519
{
492
{
520
  gfxTextRunFactory::Parameters params =
493
  gfxTextRunFactory::Parameters params =
521
    { aRefContext, nullptr, nullptr,
494
    { aRefContext, nullptr, nullptr,
522
      nullptr, 0, aTextRun->GetAppUnitsPerDevUnit()
495
      nullptr, 0, aTextRun->GetAppUnitsPerDevUnit()
523
    };
496
    };
524
  *aFlags = aTextRun->GetFlags() & ~gfxFontGroup::TEXT_IS_PERSISTENT;
497
  *aFlags = aTextRun->GetFlags() & ~gfxFontGroup::TEXT_IS_PERSISTENT;
(-)a/layout/generic/nsTextRunTransformations.h (+39 lines)
Line     Link Here 
 Lines 128-136   private: Link Here 
128
128
129
    uint32_t i;
129
    uint32_t i;
130
    for (i = 0; i < aLength; ++i) {
130
    for (i = 0; i < aLength; ++i) {
131
      mStyles.AppendElement(aStyles[i]);
131
      mStyles.AppendElement(aStyles[i]);
132
    }
132
    }
133
  }
133
  }
134
};
134
};
135
135
136
/**
137
 * Copy a given textrun, but merge certain characters into a single logical
138
 * character. Glyphs for a character are added to the glyph list for the previous
139
 * character and then the merged character is eliminated. Visually the results
140
 * are identical.
141
 *
142
 * This is used for text-transform:uppercase when we encounter a SZLIG,
143
 * whose uppercase form is "SS", or other ligature or precomposed form
144
 * that expands to multiple codepoints during case transformation,
145
 * and for Greek text when combining diacritics have been deleted.
146
 *
147
 * This function is unable to merge characters when they occur in different
148
 * glyph runs. This only happens in tricky edge cases where a character was
149
 * decomposed by case-mapping (e.g. there's no precomposed uppercase version
150
 * of an accented lowercase letter), and then font-matching caused the
151
 * diacritics to be assigned to a different font than the base character.
152
 * In this situation, the diacritic(s) get discarded, which is less than
153
 * ideal, but they probably weren't going to render very well anyway.
154
 * Bug 543200 will improve this by making font-matching operate on entire
155
 * clusters instead of individual codepoints.
156
 *
157
 * For simplicity, this produces a textrun containing all DetailedGlyphs,
158
 * no simple glyphs. So don't call it unless you really have merging to do.
159
 *
160
 * @param aCharsToMerge when aCharsToMerge[i] is true, this character in aSrc
161
 * is merged into the previous character
162
 *
163
 * @param aDeletedChars when aDeletedChars[i] is true, the character at this
164
 * position in aDest was deleted (has no corresponding char in aSrc)
165
 */
166
void
167
MergeCharactersInTextRun(gfxTextRun* aDest, gfxTextRun* aSrc,
168
                         const bool* aCharsToMerge, const bool* aDeletedChars);
169
170
gfxTextRunFactory::Parameters
171
GetParametersForInner(nsTransformedTextRun* aTextRun, uint32_t* aFlags,
172
                      gfxContext* aRefContext);
173
174
136
#endif /*NSTEXTRUNTRANSFORMATIONS_H_*/
175
#endif /*NSTEXTRUNTRANSFORMATIONS_H_*/

Return to bug 114365