First public contribution.
1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
28 static const TText16 KLatinGlyph_SoftHyphen = 0x00AD;
33 // TUtf32Iterator Class definition
38 TUint TUtf32Iterator::UTF16ToTChar(const TText16* a)
40 This routine takes an encoded UTF16 byte array and decodes the
41 first character at the start of the array and returns it as a TChar.
42 If the char is "not a char" character 0xFFFF results.
44 UTF16 byte array to be decoded.
46 Position pointer 'a' derived from, incremented if surragote pairs decoded.
48 The character value in UTF32 format or 0xFFFF it not a character.
51 // Is next char a surrogate?
52 if (0xD800 == (a[0] & 0xF800))
54 // Is it a high surrogate in the range D800..DBFF?
55 if (0xD800 == (a[0] & 0xFC00))
57 // Its a high surrogate, is the next char a low surrogate?
58 if (0xDC00 == (a[1] & 0xFC00))
60 // It's a low surrogate
61 return ((a[0] - 0xd7f7) << 10) + a[1];
74 TUtf32Iterator::TUtf32Iterator(const TText16* aStart, const TText16* aEnd, TInt aStartingIndex)
76 Construct iterator given UTF16 encoded byte array.
78 Start address of the array.
80 Address of the byte just beyond the end of the array.
82 Optional UTF16 offset into the array to initialise the current position to.
83 @panic EGdiPanic_InvalidInputParam
84 Raised when array start if passed the array end.
86 : iStart(aStart), iCurrent(aStart+aStartingIndex), iEnd(aEnd), iChar(0xffff)
88 GDI_ASSERT_DEBUG(iStart < iEnd, EGdiPanic_InvalidInputParam);
92 else if (iCurrent < iStart)
96 // Sanatise array end checking for an unpaired surrogate value
97 // so that UTF16ToTChar() does not read off the end of the array.
98 if (0xD800 == (iEnd[-1] & 0xFC00))
100 if (iCurrent == iEnd-1)
106 // Setup initial position UTF32 character value
107 iChar = UTF16ToTChar(iCurrent);
112 TChar TUtf32Iterator::Next()
114 Moves the iterator forward to the next valid UTF32 character value.
115 @return TChar The next character in the text towards the end.
116 @panic EGdiPanic_OutOfText
117 Raised when there is no next position to move to.
120 GDI_ASSERT_DEBUG(iCurrent < iEnd, EGdiPanic_OutOfText);
122 iCurrent += (iChar > 0xffff) ? 2 : 1;
124 iChar = UTF16ToTChar(iCurrent);
131 TChar TUtf32Iterator::Prev()
133 Moves the iterator backwards to the next valid UTF32 character value.
134 @return TChar The prev character in the text towards the start.
135 @panic EGdiPanic_OutOfText Raised when there is no next position to move to.
138 GDI_ASSERT_DEBUG(iCurrent >= iStart, EGdiPanic_OutOfText);
141 if (iCurrent >= iStart)
142 iChar = UTF16ToTChar(iCurrent);
149 void TUtf32Iterator::SetPos(TInt aPos)
151 Moves the iterator to the position specified by array start+offset.
153 UTF16 offset into the array to set the current position to.
154 @panic EGdiPanic_OutOfText
155 Raised when there is no next position to move to.
158 GDI_ASSERT_DEBUG(iStart+aPos <= iEnd, EGdiPanic_OutOfText);
159 GDI_ASSERT_DEBUG(iStart+aPos >= iStart, EGdiPanic_OutOfText);
161 iCurrent = iStart+aPos;
162 iChar = UTF16ToTChar(iCurrent);
166 TUint TUtf32Iterator::Get(TInt offset)
168 Returns the UTF32 char value at the offset specified. 0xFFFF may be returned
169 for unpaired surrogate and noncharacters. Does not change the current
172 UTF16 offset from current iterator position to get UTF32 char form.
174 UTF32 char value found at the iterator+offset, or 0xFFFF in error.
175 @panic EGdiPanic_OutOfText
176 Raised when offset found to be outside the bounds of the original text array.
179 GDI_ASSERT_DEBUG(iCurrent+offset >= iStart, EGdiPanic_OutOfText);
180 GDI_ASSERT_DEBUG(iCurrent+offset < iEnd, EGdiPanic_OutOfText);
182 return UTF16ToTChar(iCurrent+offset);
186 TChar TUtf32Iterator::GetThenNext()
188 Return the UTF32 value at the current position.
190 UTF32 value currently pointed to by iterator.
191 @panic EGdiPanic_EndOfText
192 Raised when current iterator position is not valid.
195 GDI_ASSERT_DEBUG(iCurrent < iEnd, EGdiPanic_OutOfText);
197 TChar current(iChar);
198 iCurrent += (iChar > 0xffff) ? 2 : 1;
200 iChar = UTF16ToTChar(iCurrent);
207 TChar TUtf32Iterator::GetThenPrev()
209 Return the UTF32 value at the current position.
211 UTF32 value currently pointed to by iterator.
212 @panic EGdiPanic_EndOfText
213 Raised when current iterator position is not valid.
216 GDI_ASSERT_DEBUG(iCurrent >= iStart, EGdiPanic_OutOfText);
218 TChar current(iChar);
220 if (iCurrent >= iStart)
221 iChar = UTF16ToTChar(iCurrent);
228 TInt TUtf32Iterator::LengthToStart() const
230 Returns the number of TText16 codes between the start point and its
233 Number of TText16 characters between array start and current iterator
237 return iCurrent-iStart;
241 TInt TUtf32Iterator::LengthToEnd() const
243 Returns the number of remaining TText16 codes still ahead of the
246 Number of TText16 characters between array current iterator position
247 and the end of the array.
250 return iEnd - iCurrent;
253 const TText16* TUtf32Iterator::CurrentPosition() const
258 void TUtf32Iterator::SetCurrentPosition(const TText16* a)
265 // TGlyphSelectionState Class definition
271 The Unicode Combining Class values recognised by the
272 GlyphSelUtils::CombineLastGlyphToBase method.
277 EArabicFathatan = 27,
278 EArabicDammatan = 28,
279 EArabicKasratan = 29,
285 ECombineBelowLeftAttached = 200,
286 ECombineBelowAttached = 202,
287 ECombineBelowRightAttached = 204,
288 ECombineLeftAttached = 208,
289 ECombineRightAttached = 210,
290 ECombineAboveLeftAttached = 212,
291 ECombineAboveAttached = 214,
292 ECombineAboveRightAttached = 216,
293 ECombineBelowLeft = 218,
295 ECombineBelowRight = 222,
298 ECombineAboveLeft = 228,
300 ECombineAboveRight = 232
305 This method is called to attach (by adjusing its bounding box) the current end
306 glyph in the output array of iParam to the base glyph bounding box based on
307 the Unicode combining class of the character.
309 The general input/output glyph selection data for the routine.
311 Input: Glyph cluster with last glyph an actual combining character. Output:
312 Bounding box of last glyph adjusted according to char combining class.
313 @param aFirstDiacritic
314 Which character in the output array to treat as the first diacritic of the
315 cluster. Usually 1, but can be more if the base class is a ligature.
317 void TGlyphSelectionState::CombineLastGlyphToBase(const TRect& aBase, TInt aFirstDiacritic)
319 // Get the bounds of all the base characters.
321 int last = iParam.iOutputGlyphs-1;
322 for (int i = aFirstDiacritic; i < last; i++)
323 base.BoundingRect(iParam.iOutput[i].iBounds);
325 // Calculate the attachment points.
326 TRect& r = iParam.iOutput[last].iBounds;
331 int left = base.iTl.iX;
332 int center = base.iTl.iX + (base.Width() - w) / 2;
333 int right = base.iBr.iX - w;
334 int below = base.iBr.iY;
335 int above = base.iTl.iY - h;
336 int left_of = left - w;
337 int right_of = right + w;
339 int yGap = iFont->HeightInPixels()/10;
341 // Select attachment based on combining class.
344 case ECombineBelowLeftAttached:
348 case ECombineBelowAttached:
352 case ECombineBelowRightAttached:
356 case ECombineLeftAttached:
359 case ECombineRightAttached:
362 case ECombineAboveLeftAttached:
366 case ECombineAboveAttached:
370 case ECombineAboveRightAttached:
374 case ECombineBelowLeft:
379 case EArabicKasratan:
384 case ECombineBelowRight:
394 case ECombineAboveLeft:
399 case EArabicFathatan:
400 case EArabicDammatan:
408 case ECombineAboveRight:
417 // Adjust the bounding box of the last glyph to fix position
418 // based on the characters combining class. For speed, do directly.
419 // r.SetRect(l,t,l + w,t + h);
427 TBool TGlyphSelectionState::AppendGlyphToCluster(TUint aCode)
429 This common method is used by glyph selector classes to add a glyph to
430 the end of the aGss.iParam output field filling in all the glyph info
433 The Unicode character for which a glyph should be appended.
435 The general input/output glyph selection data for the routine.
437 ETrue when successful, EFalse when failure occurs e..g no char data, overflow
440 // Setup reference to next free glyph record we need to update.
441 GDI_ASSERT_DEBUG(iParam.iOutputGlyphs < CFont::TPositionParam::EMaxOutputGlyphs,
442 EGdiPanic_InvalidInputParam);
444 CFont::TPositionParam::TOutput* output = iParam.iOutput+iParam.iOutputGlyphs;
446 // Retrieve the glyph details from the Font. Essential to proceed, abort
448 TOpenFontCharMetrics metrics;
449 if (iFont->GetCharacterData(aCode, metrics, output->iBitmap,
450 output->iBitmapSize) == CFont::ENoCharacterData)
453 // Set code point of glyph in output record.
454 output->iCode = aCode;
456 // Set the glyph's bounds in the output record and record pen advancement.
457 if (iParam.iDirection == CFont::EVertical)
459 metrics.GetVertBounds(output->iBounds);
460 iAdvance.iHeight = Max(iAdvance.iHeight, metrics.VertAdvance());
464 metrics.GetHorizBounds(output->iBounds);
465 iAdvance.iWidth = Max(iAdvance.iWidth, metrics.HorizAdvance());
468 // Next adjust the glyph's bounding box to offset it from the pen
469 // position (origin of drawing). For speed increment attributes directly.
470 // output->iBounds.Move(aGss.iParam.iPen);
471 output->iBounds.iTl.iX += iParam.iPen.iX;
472 output->iBounds.iBr.iX += iParam.iPen.iX;
473 output->iBounds.iTl.iY += iParam.iPen.iY;
474 output->iBounds.iBr.iY += iParam.iPen.iY;
476 // Before we exit with success, increment the glyph array counter.
477 // for the new glyph we've added here.
478 iParam.iOutputGlyphs++;
485 // GlyphSelector_SoftHyphen Class definition
489 TBool GlyphSelector_SoftHyphen::Process(TGlyphSelectionState& aGss, RShapeInfo&)
492 See this class for the method description.
496 if (!aGss.iText.AtEnd())
498 // Here we skip & don't output hyphen since its not at the end a line.
499 aGss.iPen = TGlyphSelectionState::EPenAdvance_No;
503 // If we reach here we must output hyphen.
504 if (!aGss.AppendGlyphToCluster(KLatinGlyph_SoftHyphen))
507 aGss.iPen = TGlyphSelectionState::EPenAdvance_Yes;
510 // Logic to determine if we are now at the end of the glyph cluster.
511 // Default logic, based on whether a combining mark follows or not.
513 (!aGss.iText.AtEnd() &&
514 ((aGss.iText.Get().GetCategory() & 0xF0) == TChar::EMarkGroup)) ?
515 TGlyphSelectionState::EGClusterNotComplete : TGlyphSelectionState::EGClusterComplete;
523 // GlyphSelector_Default Class definition
528 TBool GlyphSelector_Default::Process(TGlyphSelectionState& aGss, RShapeInfo&)
531 See this class for the method description.
535 // In this method we always output the glyph.
536 if (!aGss.AppendGlyphToCluster(aGss.iText.GetThenNext()))
539 // Adjust glyph's bounds further to position this character if it is a
541 if (aGss.IsCombiningClass())
543 aGss.iPen = TGlyphSelectionState::EPenAdvance_No;
545 TRect baseBounds(aGss.iParam.iOutput[0].iBounds);
546 // Get first character in this glyph cluster. In this default process function, the iCode should
547 // be Unicode Point Code.
548 TChar startChar = TChar(aGss.iParam.iOutput[0].iCode);
549 // Character index in the output array to treat as the first diacritic of the
550 // cluster. It will be used as first character for combine to. usually 1, but when
551 // the cluster starts with a combining mark, it should be set to 0.
552 TInt indexOfFirstCombining = 1;
553 TInt startCharCat = startChar.GetCategory() & 0xF0;
555 // if the first character in this cluster is a combining mark or a graphically empty character,
556 // (such as a space Character0x0020), a fake bound, formed from the Ascent of the font, will be
557 // used for combining
558 if ((startCharCat == TChar::EMarkGroup) || baseBounds.Size() == TSize(0,0))
560 // Determine the height of the combining glyph.
561 TInt glyphHeight = 0;
562 if (aGss.iParam.iOutputGlyphs == 1)
564 glyphHeight = aGss.iParam.iOutput[0].iBitmapSize.iHeight;
568 glyphHeight = aGss.iParam.iOutput[1].iBitmapSize.iHeight;
570 // Adjust Y values to a ficticious but reasonable range for it to combine to using the glyph height to adjust correctly below the font ascent.
571 baseBounds.iTl.iY = aGss.iParam.iPen.iY - aGss.iFont->AscentInPixels() + glyphHeight; //modest ascender
572 baseBounds.iBr.iY = aGss.iParam.iPen.iY; //No descender
575 if (startCharCat == TChar::EMarkGroup)
576 indexOfFirstCombining = 0;
578 aGss.CombineLastGlyphToBase(baseBounds, indexOfFirstCombining);
579 aGss.iGlyphPostCombine = TGlyphSelectionState::EGPostCombine_Yes;
582 aGss.iPen = TGlyphSelectionState::EPenAdvance_Yes;
584 // Logic to determine if we are now at the end of the glyph cluster.
585 // Default logic, based on whether a combining mark follows or not.
587 (!aGss.iText.AtEnd() &&
588 ((aGss.iText.Get().GetCategory() & 0xF0) == TChar::EMarkGroup)) ?
589 TGlyphSelectionState::EGClusterNotComplete : TGlyphSelectionState::EGClusterComplete;