diff -r 969102054596 -r 414d4b727fd9 graphicsdeviceinterface/gdi/sgdi/GlyphSel.cpp --- a/graphicsdeviceinterface/gdi/sgdi/GlyphSel.cpp Wed Aug 25 08:17:25 2010 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,593 +0,0 @@ -// Copyright (c) 2003-2009 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 -#include -#include "GlyphSel.h" -#include "GDIPANIC.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 EGdiPanic_InvalidInputParam - Raised when array start if passed the array end. -*/ -: iStart(aStart), iCurrent(aStart+aStartingIndex), iEnd(aEnd), iChar(0xffff) - { - GDI_ASSERT_DEBUG(iStart < iEnd, EGdiPanic_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 EGdiPanic_OutOfText -Raised when there is no next position to move to. -*/ - { - GDI_ASSERT_DEBUG(iCurrent < iEnd, EGdiPanic_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 EGdiPanic_OutOfText Raised when there is no next position to move to. -*/ - { - GDI_ASSERT_DEBUG(iCurrent >= iStart, EGdiPanic_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 EGdiPanic_OutOfText - Raised when there is no next position to move to. -*/ - { - GDI_ASSERT_DEBUG(iStart+aPos <= iEnd, EGdiPanic_OutOfText); - GDI_ASSERT_DEBUG(iStart+aPos >= iStart, EGdiPanic_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 EGdiPanic_OutOfText - Raised when offset found to be outside the bounds of the original text array. -*/ - { - GDI_ASSERT_DEBUG(iCurrent+offset >= iStart, EGdiPanic_OutOfText); - GDI_ASSERT_DEBUG(iCurrent+offset < iEnd, EGdiPanic_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 EGdiPanic_EndOfText - Raised when current iterator position is not valid. -*/ - { - GDI_ASSERT_DEBUG(iCurrent < iEnd, EGdiPanic_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 EGdiPanic_EndOfText - Raised when current iterator position is not valid. -*/ - { - GDI_ASSERT_DEBUG(iCurrent >= iStart, EGdiPanic_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. - GDI_ASSERT_DEBUG(iParam.iOutputGlyphs < CFont::TPositionParam::EMaxOutputGlyphs, - EGdiPanic_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; - } -