--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/fontservices/textbase/sgdi/GlyphSel.cpp Mon Jul 12 14:38:26 2010 +0800
@@ -0,0 +1,593 @@
+// Copyright (c) 2003-2010 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+
+//#include <textbase.h>
+#include <openfont.h>
+#include "GlyphSel.h"
+#include "TextBasePanic.h"
+
+
+static const TText16 KLatinGlyph_SoftHyphen = 0x00AD;
+
+
+//
+//
+// TUtf32Iterator Class definition
+//
+//
+
+
+TUint TUtf32Iterator::UTF16ToTChar(const TText16* a)
+/**
+ This routine takes an encoded UTF16 byte array and decodes the
+ first character at the start of the array and returns it as a TChar.
+ If the char is "not a char" character 0xFFFF results.
+@param a
+ UTF16 byte array to be decoded.
+@param aPr
+ Position pointer 'a' derived from, incremented if surragote pairs decoded.
+@return
+ The character value in UTF32 format or 0xFFFF it not a character.
+*/
+ {
+ // Is next char a surrogate?
+ if (0xD800 == (a[0] & 0xF800))
+ {
+ // Is it a high surrogate in the range D800..DBFF?
+ if (0xD800 == (a[0] & 0xFC00))
+ {
+ // Its a high surrogate, is the next char a low surrogate?
+ if (0xDC00 == (a[1] & 0xFC00))
+ {
+ // It's a low surrogate
+ return ((a[0] - 0xd7f7) << 10) + a[1];
+ }
+ else
+ return 0xFFFF;
+ }
+ else
+ return 0xFFFF;
+ }
+ else
+ return a[0];
+ }
+
+
+TUtf32Iterator::TUtf32Iterator(const TText16* aStart, const TText16* aEnd, TInt aStartingIndex)
+/**
+ Construct iterator given UTF16 encoded byte array.
+@param aStart
+ Start address of the array.
+@param aEnd
+ Address of the byte just beyond the end of the array.
+@param aStartingIndex
+ Optional UTF16 offset into the array to initialise the current position to.
+@panic ETextBasePanic_InvalidInputParam
+ Raised when array start if passed the array end.
+*/
+: iStart(aStart), iCurrent(aStart+aStartingIndex), iEnd(aEnd), iChar(0xffff)
+ {
+ TEXTBASE_ASSERT_DEBUG(iStart < iEnd, ETextBasePanic_InvalidInputParam);
+
+ if (iCurrent > iEnd)
+ iCurrent = iEnd;
+ else if (iCurrent < iStart)
+ iCurrent = iStart;
+ else
+ {
+ // Sanatise array end checking for an unpaired surrogate value
+ // so that UTF16ToTChar() does not read off the end of the array.
+ if (0xD800 == (iEnd[-1] & 0xFC00))
+ {
+ if (iCurrent == iEnd-1)
+ ++iCurrent;
+ else
+ --iEnd;
+ }
+
+ // Setup initial position UTF32 character value
+ iChar = UTF16ToTChar(iCurrent);
+ }
+ }
+
+
+TChar TUtf32Iterator::Next()
+/**
+Moves the iterator forward to the next valid UTF32 character value.
+@return TChar The next character in the text towards the end.
+@panic ETextBasePanic_OutOfText
+Raised when there is no next position to move to.
+*/
+ {
+ TEXTBASE_ASSERT_DEBUG(iCurrent < iEnd, ETextBasePanic_OutOfText);
+
+ iCurrent += (iChar > 0xffff) ? 2 : 1;
+ if (iCurrent < iEnd)
+ iChar = UTF16ToTChar(iCurrent);
+ else
+ iChar = 0xFFFF;
+ return iChar;
+ }
+
+
+TChar TUtf32Iterator::Prev()
+/**
+Moves the iterator backwards to the next valid UTF32 character value.
+@return TChar The prev character in the text towards the start.
+@panic ETextBasePanic_OutOfText Raised when there is no next position to move to.
+*/
+ {
+ TEXTBASE_ASSERT_DEBUG(iCurrent >= iStart, ETextBasePanic_OutOfText);
+
+ --iCurrent;
+ if (iCurrent >= iStart)
+ iChar = UTF16ToTChar(iCurrent);
+ else
+ iChar = 0xFFFF;
+ return iChar;
+ }
+
+
+void TUtf32Iterator::SetPos(TInt aPos)
+/**
+ Moves the iterator to the position specified by array start+offset.
+@param aPos
+ UTF16 offset into the array to set the current position to.
+@panic ETextBasePanic_OutOfText
+ Raised when there is no next position to move to.
+*/
+ {
+ TEXTBASE_ASSERT_DEBUG(iStart+aPos <= iEnd, ETextBasePanic_OutOfText);
+ TEXTBASE_ASSERT_DEBUG(iStart+aPos >= iStart, ETextBasePanic_OutOfText);
+
+ iCurrent = iStart+aPos;
+ iChar = UTF16ToTChar(iCurrent);
+ }
+
+
+TUint TUtf32Iterator::Get(TInt offset)
+/**
+ Returns the UTF32 char value at the offset specified. 0xFFFF may be returned
+ for unpaired surrogate and noncharacters. Does not change the current
+ position.
+@param offset
+ UTF16 offset from current iterator position to get UTF32 char form.
+@return TChar
+ UTF32 char value found at the iterator+offset, or 0xFFFF in error.
+@panic ETextBasePanic_OutOfText
+ Raised when offset found to be outside the bounds of the original text array.
+*/
+ {
+ TEXTBASE_ASSERT_DEBUG(iCurrent+offset >= iStart, ETextBasePanic_OutOfText);
+ TEXTBASE_ASSERT_DEBUG(iCurrent+offset < iEnd, ETextBasePanic_OutOfText);
+
+ return UTF16ToTChar(iCurrent+offset);
+ }
+
+
+TChar TUtf32Iterator::GetThenNext()
+/**
+ Return the UTF32 value at the current position.
+@return TChar
+ UTF32 value currently pointed to by iterator.
+@panic ETextBasePanic_EndOfText
+ Raised when current iterator position is not valid.
+*/
+ {
+ TEXTBASE_ASSERT_DEBUG(iCurrent < iEnd, ETextBasePanic_OutOfText);
+
+ TChar current(iChar);
+ iCurrent += (iChar > 0xffff) ? 2 : 1;
+ if (iCurrent < iEnd)
+ iChar = UTF16ToTChar(iCurrent);
+ else
+ iChar = 0xFFFF;
+ return current;
+ }
+
+
+TChar TUtf32Iterator::GetThenPrev()
+/**
+ Return the UTF32 value at the current position.
+@return TChar
+ UTF32 value currently pointed to by iterator.
+@panic ETextBasePanic_EndOfText
+ Raised when current iterator position is not valid.
+*/
+ {
+ TEXTBASE_ASSERT_DEBUG(iCurrent >= iStart, ETextBasePanic_OutOfText);
+
+ TChar current(iChar);
+ --iCurrent;
+ if (iCurrent >= iStart)
+ iChar = UTF16ToTChar(iCurrent);
+ else
+ iChar = 0xFFFF;
+ return current;
+ }
+
+
+TInt TUtf32Iterator::LengthToStart() const
+/**
+ Returns the number of TText16 codes between the start point and its
+ current position.
+@return TInt
+ Number of TText16 characters between array start and current iterator
+ position.
+*/
+ {
+ return iCurrent-iStart;
+ }
+
+
+TInt TUtf32Iterator::LengthToEnd() const
+/**
+ Returns the number of remaining TText16 codes still ahead of the
+ iterator.
+@return TInt
+ Number of TText16 characters between array current iterator position
+ and the end of the array.
+*/
+ {
+ return iEnd - iCurrent;
+ }
+
+const TText16* TUtf32Iterator::CurrentPosition() const
+ {
+ return iCurrent;
+ }
+
+void TUtf32Iterator::SetCurrentPosition(const TText16* a)
+ {
+ iCurrent = a;
+ }
+
+//
+//
+// TGlyphSelectionState Class definition
+//
+//
+
+
+/**
+ The Unicode Combining Class values recognised by the
+ GlyphSelUtils::CombineLastGlyphToBase method.
+@internalComponent
+*/
+enum TCombiningClass
+ {
+ EArabicFathatan = 27,
+ EArabicDammatan = 28,
+ EArabicKasratan = 29,
+ EArabicFatha = 30,
+ EArabicDamma = 31,
+ EArabicKasra = 32,
+ EArabicShadda = 33,
+ EArabicSukun = 34,
+ ECombineBelowLeftAttached = 200,
+ ECombineBelowAttached = 202,
+ ECombineBelowRightAttached = 204,
+ ECombineLeftAttached = 208,
+ ECombineRightAttached = 210,
+ ECombineAboveLeftAttached = 212,
+ ECombineAboveAttached = 214,
+ ECombineAboveRightAttached = 216,
+ ECombineBelowLeft = 218,
+ ECombineBelow = 220,
+ ECombineBelowRight = 222,
+ ECombineLeft = 224,
+ ECombineRight = 226,
+ ECombineAboveLeft = 228,
+ ECombineAbove = 230,
+ ECombineAboveRight = 232
+ };
+
+
+/**
+ This method is called to attach (by adjusing its bounding box) the current end
+ glyph in the output array of iParam to the base glyph bounding box based on
+ the Unicode combining class of the character.
+@param aGss
+ The general input/output glyph selection data for the routine.
+@param aGss.iOutput
+ Input: Glyph cluster with last glyph an actual combining character. Output:
+ Bounding box of last glyph adjusted according to char combining class.
+@param aFirstDiacritic
+ Which character in the output array to treat as the first diacritic of the
+ cluster. Usually 1, but can be more if the base class is a ligature.
+*/
+void TGlyphSelectionState::CombineLastGlyphToBase(const TRect& aBase, TInt aFirstDiacritic)
+ {
+ // Get the bounds of all the base characters.
+ TRect base = aBase;
+ int last = iParam.iOutputGlyphs-1;
+ for (int i = aFirstDiacritic; i < last; i++)
+ base.BoundingRect(iParam.iOutput[i].iBounds);
+
+ // Calculate the attachment points.
+ TRect& r = iParam.iOutput[last].iBounds;
+ int w = r.Width();
+ int h = r.Height();
+ int t = r.iTl.iY;
+ int l = r.iTl.iX;
+ int left = base.iTl.iX;
+ int center = base.iTl.iX + (base.Width() - w) / 2;
+ int right = base.iBr.iX - w;
+ int below = base.iBr.iY;
+ int above = base.iTl.iY - h;
+ int left_of = left - w;
+ int right_of = right + w;
+ int xGap = 1;
+ int yGap = iFont->HeightInPixels()/10;
+
+ // Select attachment based on combining class.
+ switch (iCombCls)
+ {
+ case ECombineBelowLeftAttached:
+ t = below;
+ l = left;
+ break;
+ case ECombineBelowAttached:
+ t = below;
+ l = center;
+ break;
+ case ECombineBelowRightAttached:
+ t = below;
+ l = right;
+ break;
+ case ECombineLeftAttached:
+ l = left_of;
+ break;
+ case ECombineRightAttached:
+ l = right_of;
+ break;
+ case ECombineAboveLeftAttached:
+ t = above;
+ l = left;
+ break;
+ case ECombineAboveAttached:
+ t = above;
+ l = center;
+ break;
+ case ECombineAboveRightAttached:
+ t = above;
+ l = right;
+ break;
+ case ECombineBelowLeft:
+ t = below + yGap;
+ l = left;
+ break;
+ case ECombineBelow:
+ case EArabicKasratan:
+ case EArabicKasra:
+ t = below + yGap;
+ l = center;
+ break;
+ case ECombineBelowRight:
+ t = below + yGap;
+ l = right;
+ break;
+ case ECombineLeft:
+ l = left_of - xGap;
+ break;
+ case ECombineRight:
+ l = right_of + xGap;
+ break;
+ case ECombineAboveLeft:
+ t = above - yGap;
+ l = left;
+ break;
+ case ECombineAbove:
+ case EArabicFathatan:
+ case EArabicDammatan:
+ case EArabicFatha:
+ case EArabicDamma:
+ case EArabicShadda:
+ case EArabicSukun:
+ t = above - yGap;
+ l = center;
+ break;
+ case ECombineAboveRight:
+ t = above - yGap;
+ l = right;
+ break;
+ default:
+ l = center;
+ break;
+ }
+
+ // Adjust the bounding box of the last glyph to fix position
+ // based on the characters combining class. For speed, do directly.
+ // r.SetRect(l,t,l + w,t + h);
+ r.iTl.iX = l;
+ r.iTl.iY = t;
+ r.iBr.iX = l+w;
+ r.iBr.iY = t+h;
+ }
+
+
+TBool TGlyphSelectionState::AppendGlyphToCluster(TUint aCode)
+/**
+ This common method is used by glyph selector classes to add a glyph to
+ the end of the aGss.iParam output field filling in all the glyph info
+ needed.
+@param aCode
+ The Unicode character for which a glyph should be appended.
+@param aGss
+ The general input/output glyph selection data for the routine.
+@return TBool
+ ETrue when successful, EFalse when failure occurs e..g no char data, overflow
+*/
+ {
+ // Setup reference to next free glyph record we need to update.
+ TEXTBASE_ASSERT_DEBUG(iParam.iOutputGlyphs < CFont::TPositionParam::EMaxOutputGlyphs,
+ ETextBasePanic_InvalidInputParam);
+
+ CFont::TPositionParam::TOutput* output = iParam.iOutput+iParam.iOutputGlyphs;
+
+ // Retrieve the glyph details from the Font. Essential to proceed, abort
+ // if not available.
+ TOpenFontCharMetrics metrics;
+ if (iFont->GetCharacterData(aCode, metrics, output->iBitmap,
+ output->iBitmapSize) == CFont::ENoCharacterData)
+ return EFalse;
+
+ // Set code point of glyph in output record.
+ output->iCode = aCode;
+
+ // Set the glyph's bounds in the output record and record pen advancement.
+ if (iParam.iDirection == CFont::EVertical)
+ {
+ metrics.GetVertBounds(output->iBounds);
+ iAdvance.iHeight = Max(iAdvance.iHeight, metrics.VertAdvance());
+ }
+ else
+ {
+ metrics.GetHorizBounds(output->iBounds);
+ iAdvance.iWidth = Max(iAdvance.iWidth, metrics.HorizAdvance());
+ }
+
+ // Next adjust the glyph's bounding box to offset it from the pen
+ // position (origin of drawing). For speed increment attributes directly.
+ // output->iBounds.Move(aGss.iParam.iPen);
+ output->iBounds.iTl.iX += iParam.iPen.iX;
+ output->iBounds.iBr.iX += iParam.iPen.iX;
+ output->iBounds.iTl.iY += iParam.iPen.iY;
+ output->iBounds.iBr.iY += iParam.iPen.iY;
+
+ // Before we exit with success, increment the glyph array counter.
+ // for the new glyph we've added here.
+ iParam.iOutputGlyphs++;
+ return ETrue;
+ }
+
+
+//
+//
+// GlyphSelector_SoftHyphen Class definition
+//
+//
+
+TBool GlyphSelector_SoftHyphen::Process(TGlyphSelectionState& aGss, RShapeInfo&)
+/**
+@see GlyphSelUtils
+ See this class for the method description.
+*/
+ {
+ aGss.iText.Next();
+ if (!aGss.iText.AtEnd())
+ {
+ // Here we skip & don't output hyphen since its not at the end a line.
+ aGss.iPen = TGlyphSelectionState::EPenAdvance_No;
+ }
+ else
+ {
+ // If we reach here we must output hyphen.
+ if (!aGss.AppendGlyphToCluster(KLatinGlyph_SoftHyphen))
+ return EFalse;
+
+ aGss.iPen = TGlyphSelectionState::EPenAdvance_Yes;
+ }
+
+ // Logic to determine if we are now at the end of the glyph cluster.
+ // Default logic, based on whether a combining mark follows or not.
+ aGss.iClusterState =
+ (!aGss.iText.AtEnd() &&
+ ((aGss.iText.Get().GetCategory() & 0xF0) == TChar::EMarkGroup)) ?
+ TGlyphSelectionState::EGClusterNotComplete : TGlyphSelectionState::EGClusterComplete;
+
+ return ETrue;
+ }
+
+
+//
+//
+// GlyphSelector_Default Class definition
+//
+//
+
+
+TBool GlyphSelector_Default::Process(TGlyphSelectionState& aGss, RShapeInfo&)
+/**
+@see GlyphSelUtils
+ See this class for the method description.
+*/
+ {
+
+ // In this method we always output the glyph.
+ if (!aGss.AppendGlyphToCluster(aGss.iText.GetThenNext()))
+ return EFalse;
+
+ // Adjust glyph's bounds further to position this character if it is a
+ // combining mark
+ if (aGss.IsCombiningClass())
+ {
+ aGss.iPen = TGlyphSelectionState::EPenAdvance_No;
+
+ TRect baseBounds(aGss.iParam.iOutput[0].iBounds);
+ // Get first character in this glyph cluster. In this default process function, the iCode should
+ // be Unicode Point Code.
+ TChar startChar = TChar(aGss.iParam.iOutput[0].iCode);
+ // Character index in the output array to treat as the first diacritic of the
+ // cluster. It will be used as first character for combine to. usually 1, but when
+ // the cluster starts with a combining mark, it should be set to 0.
+ TInt indexOfFirstCombining = 1;
+ TInt startCharCat = startChar.GetCategory() & 0xF0;
+
+ // if the first character in this cluster is a combining mark or a graphically empty character,
+ // (such as a space Character0x0020), a fake bound, formed from the Ascent of the font, will be
+ // used for combining
+ if ((startCharCat == TChar::EMarkGroup) || baseBounds.Size() == TSize(0,0))
+ {
+ // Determine the height of the combining glyph.
+ TInt glyphHeight = 0;
+ if (aGss.iParam.iOutputGlyphs == 1)
+ {
+ glyphHeight = aGss.iParam.iOutput[0].iBitmapSize.iHeight;
+ }
+ else
+ {
+ glyphHeight = aGss.iParam.iOutput[1].iBitmapSize.iHeight;
+ }
+ // 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.
+ baseBounds.iTl.iY = aGss.iParam.iPen.iY - aGss.iFont->AscentInPixels() + glyphHeight; //modest ascender
+ baseBounds.iBr.iY = aGss.iParam.iPen.iY; //No descender
+ }
+
+ if (startCharCat == TChar::EMarkGroup)
+ indexOfFirstCombining = 0;
+
+ aGss.CombineLastGlyphToBase(baseBounds, indexOfFirstCombining);
+ aGss.iGlyphPostCombine = TGlyphSelectionState::EGPostCombine_Yes;
+ }
+ else
+ aGss.iPen = TGlyphSelectionState::EPenAdvance_Yes;
+
+ // Logic to determine if we are now at the end of the glyph cluster.
+ // Default logic, based on whether a combining mark follows or not.
+ aGss.iClusterState =
+ (!aGss.iText.AtEnd() &&
+ ((aGss.iText.Get().GetCategory() & 0xF0) == TChar::EMarkGroup)) ?
+ TGlyphSelectionState::EGClusterNotComplete : TGlyphSelectionState::EGClusterComplete;
+
+ return ETrue;
+ }
+