textfuns.cpp

Go to the documentation of this file.
00001 // $Id: textfuns.cpp 1495 2006-07-22 12:27:56Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 // Implementation of the TEXT tool
00099 
00100 /*
00101 */
00102 
00103 #include "camtypes.h"
00104 #include "textfuns.h"
00105 
00106 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 #include "camelot.h"
00108 #include "fontman.h"
00109 #ifndef EXCLUDE_FROM_XARALX
00110 #include "atmfonts.h"
00111 #endif
00112 #include "unicdman.h"
00113 
00114 DECLARE_SOURCE( "$Revision: 1495 $" );
00115 
00116 CC_IMPLEMENT_MEMDUMP( CharMetrics, CC_CLASS_MEMDUMP );
00117 
00118 #define new CAM_DEBUG_NEW     
00119 
00120 
00122 // CharMetrics
00123 
00124 /***************************************************************************************
00125 >   CharMetrics::CharMetrics()
00126 
00127     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00128     Created:    15/1/96
00129     Purpose:    default constructorGet the path associated with a given char
00130 ********************************************************************************************/
00131 
00132 CharMetrics::CharMetrics()
00133 {
00134     CharWidth   = 0;
00135     FontAscent  = 0;
00136     FontDescent = 0;
00137     FontEmWidth = 0;
00138 }
00139 
00140 
00141 /***************************************************************************************
00142 >   BOOL CharMetrics::Scale(double ScaleX, double ScaleY)
00143 
00144     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00145     Created:    17/1/96
00146     Inputs:     ScaleX - 
00147                 ScaleY - 
00148     Purpose:    Scale the metrics by the x/y scale factors
00149 ********************************************************************************************/
00150 
00151 void CharMetrics::Scale(double ScaleX, double ScaleY)
00152 {
00153     CharWidth   = (MILLIPOINT)(CharWidth   * ScaleX + 0.5);
00154     FontEmWidth = (MILLIPOINT)(FontEmWidth * ScaleX + 0.5);
00155     FontAscent  = (MILLIPOINT)(FontAscent  * ScaleY + 0.5);
00156     FontDescent = (MILLIPOINT)(FontDescent * ScaleY + 0.5);
00157 }
00158 
00159 
00161 // TextManager
00162 
00163 /***************************************************************************************
00164 >   static BOOL TextManager::GetTTCharPath(CharDescription& ChDesc, DocCoord** ppCoords,
00165                                          PathVerb** ppVerbs, UINT32* pNumCoords, wxDC* pDC=NULL)
00166 
00167     Author:     Mark_Goodall (Xara Group Ltd) <camelotdev@xara.com>
00168     Created:    21/3/95
00169     Inputs:     ChDesc= description of char
00170                 pDC= (possible) pointer to a DC (for optimisation) defaults to NULL
00171     Outputs:    ppCoords=>pointer to path coords buffer
00172                 ppVerbs=>pointer to path verbs buffer
00173                 pNumCoords=number of elements in path
00174     Returns:    FALSE if fails
00175     Purpose:    Get the path associated with a given char
00176     Global:     Assumes MM_TextMode 
00177 ********************************************************************************************/
00178 
00179 BOOL TextManager::GetTTCharPath(CharDescription& ChDesc, DocCoord** ppCoords,
00180                               PathVerb** ppVerbs, UINT32* pNumCoords, wxDC* pDC)
00181 {
00182 PORTNOTE("text", "no TrueType font manager in wxOil")
00183 #ifndef EXCLUDE_FROM_XARALX
00184     ERROR2IF(ppCoords==NULL,FALSE,"TextManager::GetTTCharPath pCoords==NULL");
00185     ERROR2IF(ppVerbs==NULL,FALSE,"TextManager::GetTTCharPath ppVerbs==NULL");
00186     ERROR2IF(pNumCoords==NULL,FALSE,"TextManager::GetTTCharPath pNumCoords==NULL");
00187 
00188     const  CharPathBufferSize=2048;
00189     static DocCoord CharPathCoordArray[CharPathBufferSize];
00190     static PathVerb CharPathVerbArray[CharPathBufferSize];
00191 
00192     // ensure we have a DC
00193     BOOL LocalDC=(pDC==NULL);
00194     if (LocalDC)
00195     {
00196         pDC=new CDC;
00197         if (pDC==NULL)
00198         {
00199             ERROR3("TextManager::GetCharPath() - failed to create DC");
00200             return FALSE;
00201         }
00202         if (pDC->CreateCompatibleDC(NULL)==FALSE)
00203         {
00204             delete pDC;
00205             ERROR3("TextManager::GetCharPath() - CreateCompatibleDC() failed");
00206             return FALSE;
00207         }
00208     }
00209     
00210     // get a log font from the char description, then the path data from the logfont
00211     LOGFONT CharLogFont;
00212     BOOL ok=GetLogFontFromCharDescriptor(pDC, ChDesc, &CharLogFont);
00213     UINT32 Coords=CharPathBufferSize;
00214     if (ok)
00215     {
00216         ok=GetBezierFromChar(pDC, ChDesc.GetCharCode(), &CharLogFont, &Coords, (POINT*)CharPathCoordArray, CharPathVerbArray);
00217         
00218         // If that failed try again with the default character
00219         if (!ok)
00220         {
00221             // Get the default character to use if a charater is not present in the font.
00222             WCHAR DefChar = (unsigned char)'?';
00223             TEXTMETRIC FontTextData;
00224 #ifdef _UNCCODE
00225             if (pDC->GetTextMetrics(&FontTextData))
00226                 DefChar = FontTextData.tmDefaultChar;
00227 #else
00228             if (pDC->GetTextMetrics(&FontTextData))
00229                 DefChar = (unsigned char)FontTextData.tmDefaultChar;
00230 #endif
00231 
00232             ok = GetBezierFromChar(pDC, DefChar, &CharLogFont, &Coords, (POINT*)CharPathCoordArray, CharPathVerbArray);
00233         }
00234 
00235         ERROR3IF(!ok, "TextManager::GetCharPath error from GetBezierFromChar");
00236     }
00237 
00238     // if ok, set outputs, tidy up and return
00239     if (ok)
00240     {
00241         *ppCoords   = CharPathCoordArray;
00242         *ppVerbs    = CharPathVerbArray;
00243         *pNumCoords = Coords;
00244     }
00245     if (LocalDC) delete pDC;
00246     return ok;
00247 #else
00248     return FALSE;
00249 #endif
00250 }
00251 
00252 
00253 /***************************************************************************************
00254 >   static BOOL TextManager::GetBezierFromChar(wxDC* pDC,const WCHAR CharNumber,
00255                                                LPLOGFONT pLogFont, DWORD* NoPolyElements,
00256                                                POINT* pPolyCordBuffer, BYTE* pPolyVerbBuffer)
00257 
00258     Author:     Mark_Goodall (Xara Group Ltd) <camelotdev@xara.com>
00259     Created:    25/1/95
00260     Purpose:    To generate the bezier paths which represent a character from a TrueType and, eventually, an ATM, font character
00261     Inputs:     pDC=>device context
00262                 CharNumber=character number of char this is a wide Unicode value
00263                 pLogFontStruct=>LOGFONT struct defining char, the size field is in logcords (=device cords in MM_TextMode) 
00264                 NoPolyElements=Number of elements in PolyDraw arrays, 
00265                     If NoPolyElements=0 then NoPolyElements is set to no. of elements required
00266                     If NoPolyElements<>0 then generate paths in PolyDraw arrays
00267                 pPolyCordBuffer=>Cord array in PolyDraw system
00268                 pPolyVerbBuffer=>Verb array in PolyDraw system
00269     Global:     Assumes MM_TextMode 
00270     Outputs:    NoPolyElements=No. required if entry value=0
00271                 PolyDrawArrays (Verb,Cord) filled if NoPolyElements<>0, CordArrays hold cords in 1/72000's
00272     Returns:    If FALSE returned then error has occured
00273 ********************************************************************************************/
00274         
00275 #define FIXEDTOINT32(FIXED) (*((INT32 *)&FIXED))
00276 #define SCALEX(jobby) (MulDiv(MulDiv(jobby,72000,DivConstX),pLogFont->lfHeight,-4096))
00277 #define SCALEY(jobby) (MulDiv(MulDiv(jobby,72000,DivConstY),pLogFont->lfHeight,-4096))  
00278    
00279 BOOL TextManager::GetBezierFromChar(wxDC* pDC,WCHAR CharNumber,
00280  LPLOGFONT pLogFont, DWORD* NoPolyElements, POINT* pPolyCordBuffer, BYTE* pPolyVerbBuffer)
00281 {
00282 PORTNOTE("text", "no TrueType font manager in wxOil")
00283 #ifndef EXCLUDE_FROM_XARALX
00284     if (*NoPolyElements==0)
00285     { 
00286         *NoPolyElements=2000; // Assume that 500 element array is big enough, although we still check on this later!!
00287         return TRUE;
00288     }        
00289 
00290     INT32 DivConstX=pDC->GetDeviceCaps(LOGPIXELSX)<<16;
00291     INT32 DivConstY=pDC->GetDeviceCaps(LOGPIXELSY)<<16;
00292     
00293     LOGFONT TempLogFont=*pLogFont;
00294     TempLogFont.lfHeight=-4096;//This ought to be -2048 but this doesn't return correct outlines on Times Italic on o's etc
00295     TempLogFont.lfWidth=0;
00296     CFont UnHintedCFont;
00297     UnHintedCFont.CreateFontIndirect(&TempLogFont);
00298     CFont* pOldCFont=pDC->SelectObject(&UnHintedCFont);
00299     
00300     MAT2 DefaultMatrix={ {0,1} ,{0,0}, {0,0}, {0,1} };
00301     TEXTMETRIC ATextMetricStruct;
00302     pDC->GetTextMetrics(&ATextMetricStruct);
00303     GLYPHMETRICS GlyphMetricsBuffer;
00304         
00305     // Get the size of the glyph data
00306     DWORD SizeOfGlyphData = (DWORD)-1;
00307     UINT32 MBChar = 0;
00308     if (UnicodeManager::IsUnicodeCompleteOS())
00309         SizeOfGlyphData = GetGlyphOutlineW(pDC->GetSafeHdc(), CharNumber, GGO_NATIVE, &GlyphMetricsBuffer, 0, NULL, &DefaultMatrix);
00310     else
00311     {
00312         MBChar = UnicodeManager::UnicodeToMultiByte(CharNumber);
00313         SizeOfGlyphData = GetGlyphOutlineA(pDC->GetSafeHdc(), MBChar, GGO_NATIVE, &GlyphMetricsBuffer, 0, NULL, &DefaultMatrix);
00314     }
00315     if (SizeOfGlyphData==-1)
00316         return FALSE;
00317 
00318     // claim memory for glyph data
00319     BYTE* pGlyphBuffer= new BYTE[SizeOfGlyphData];
00320     if (pGlyphBuffer == NULL)
00321         return FALSE;
00322 
00323     // Get the glyph outline data
00324     DWORD Error = (DWORD)-1;
00325     if (UnicodeManager::IsUnicodeCompleteOS())
00326         Error = GetGlyphOutlineW(pDC->GetSafeHdc(), CharNumber, GGO_NATIVE, &GlyphMetricsBuffer, SizeOfGlyphData, pGlyphBuffer, &DefaultMatrix);
00327     else
00328         Error = GetGlyphOutlineA(pDC->GetSafeHdc(), MBChar, GGO_NATIVE, &GlyphMetricsBuffer, SizeOfGlyphData, pGlyphBuffer, &DefaultMatrix);
00329 
00330     if (Error == -1)
00331     {
00332         delete[] pGlyphBuffer;
00333         ERROR2(FALSE, "GetGlyphOutline failed");
00334     }
00335 
00336     //Lets restore the DC font status
00337     pDC->SelectObject(pOldCFont);
00338     
00339     // We now have the GlyphOutline structure in the GlyphBuffer, this consists of TTPolygon etc headers 
00340     // and records
00341     
00342     BYTE* pPosInGlyphBuffer=(BYTE*)pGlyphBuffer;// pointer to our current position in GlyphBuffer
00343     DWORD ContourSize;                          // size of data controlled by a PolyHeader structure
00344     TTPOLYGONHEADER* pPolyHeader;               // needed to allow access to structure data
00345     TTPOLYCURVE* pPolyCurve;                    // ditto
00346     DWORD   CurrentPolyIndex=0;                 // Current index in the output PolyBuffer holding beziers etc
00347     WORD    NoOfArrayElements;                  // No of elements in a Qspline or prim_line record
00348     INT32   CurrentX;                           // Last point of current path (line or quad b-spline) or previous one
00349     INT32   CurrentY;
00350     DWORD   FirstContourIndex;                  // The index in PolyCordBuffer of the first member of the current contour
00351 
00352     while (pPosInGlyphBuffer<(BYTE*)pGlyphBuffer+SizeOfGlyphData) 
00353     {
00354         // Right lets process a TTPOLYGONHEADER and its associated spline and line records  
00355         pPolyHeader=(TTPOLYGONHEADER*)pPosInGlyphBuffer;
00356         ContourSize=pPolyHeader->cb;
00357         CurrentX=FIXEDTOINT32(pPolyHeader->pfxStart.x);
00358         CurrentY=FIXEDTOINT32(pPolyHeader->pfxStart.y);
00359         pPolyCordBuffer[CurrentPolyIndex].x=SCALEX(CurrentX); // First entry is always MoveTo to set 1st point of bezier etc
00360         pPolyCordBuffer[CurrentPolyIndex].y=SCALEY(CurrentY);
00361         pPolyVerbBuffer[CurrentPolyIndex]  =PT_MOVETO;
00362         FirstContourIndex=CurrentPolyIndex;
00363         CurrentPolyIndex++;                          
00364                                 
00365         pPosInGlyphBuffer=pPosInGlyphBuffer+sizeof(TTPOLYGONHEADER);  // pPosInGlyphBuffer=>1st TTPOLYCURVE
00366         
00367         // Lets process all the TTPOLYGONCURVE structs that exist within the current TTPOLYGONHEADER domain (contour)
00368         do
00369         {
00370             if (CurrentPolyIndex+4>=*NoPolyElements)                  // are we overflowing poly draw buffer
00371             {
00372                 delete[] pGlyphBuffer;
00373                 TRACE( _T("overflowing polydraw buffer"));
00374                 return FALSE;
00375             }
00376 
00377             pPolyCurve=(TTPOLYCURVE*)pPosInGlyphBuffer;
00378             NoOfArrayElements=pPolyCurve->cpfx;
00379             
00380             DWORD i;
00381             switch (pPolyCurve->wType)
00382             {   
00383                 case TT_PRIM_LINE:
00384                 for (i=0;i<NoOfArrayElements;i++)
00385                 {
00386                     CurrentX=FIXEDTOINT32(pPolyCurve->apfx[i].x);
00387                     pPolyCordBuffer[CurrentPolyIndex].x=SCALEX(CurrentX); // First entry is always MoveTo to set 1st point of bezier etc
00388                     CurrentY=FIXEDTOINT32(pPolyCurve->apfx[i].y);
00389                     pPolyCordBuffer[CurrentPolyIndex].y=SCALEY(CurrentY);
00390                     pPolyVerbBuffer[CurrentPolyIndex]=PT_LINETO;
00391                     CurrentPolyIndex++;
00392                 }
00393                 break;
00394 
00395                 
00396                 case TT_PRIM_QSPLINE:
00397                 
00398                 for ( i=0;i+1<NoOfArrayElements;i++)
00399                 {
00400                     pPolyVerbBuffer[CurrentPolyIndex]=PT_BEZIERTO;
00401                     pPolyVerbBuffer[CurrentPolyIndex+1]=PT_BEZIERTO;
00402                     pPolyVerbBuffer[CurrentPolyIndex+2]=PT_BEZIERTO;
00403 
00404                     //TRACE( _T("i=%d\n"),i);
00405                     // Lets set CurrentPolyIndex [+0] & [+1]
00406                     pPolyCordBuffer[CurrentPolyIndex].x=
00407 // This can overflow - best to scale the components separately
00408 //                  SCALEX((CurrentX+((FIXEDTOINT32(pPolyCurve->apfx[i].x))<<1))/3);
00409                     SCALEX(CurrentX/3) + SCALEX(((FIXEDTOINT32(pPolyCurve->apfx[i].x))<<1)/3);
00410                     
00411                     pPolyCordBuffer[CurrentPolyIndex].y=
00412 // This can overflow - best to scale the components separately
00413 //                  SCALEY((CurrentY+((FIXEDTOINT32(pPolyCurve->apfx[i].y))<<1))/3);
00414                     SCALEY(CurrentY/3) + SCALEY(((FIXEDTOINT32(pPolyCurve->apfx[i].y))<<1)/3);
00415                     
00416                     if (i+2==NoOfArrayElements)  // are we on last processable point in record?
00417                     { // yes we are, so just get last point
00418                         CurrentX=FIXEDTOINT32(pPolyCurve->apfx[i+1].x);
00419                         pPolyCordBuffer[CurrentPolyIndex+2].x=SCALEX(CurrentX);
00420                         CurrentY=FIXEDTOINT32(pPolyCurve->apfx[i+1].y); 
00421                         pPolyCordBuffer[CurrentPolyIndex+2].y=SCALEY(CurrentY); 
00422                     }
00423                     else 
00424                     { // no we're not, so we have to calculate midpoint between the two following points
00425                         CurrentX=(FIXEDTOINT32(pPolyCurve->apfx[i].x)+FIXEDTOINT32(pPolyCurve->apfx[i+1].x))>>1;
00426                         pPolyCordBuffer[CurrentPolyIndex+2].x=SCALEX(CurrentX);
00427                         CurrentY=(FIXEDTOINT32(pPolyCurve->apfx[i].y)+FIXEDTOINT32(pPolyCurve->apfx[i+1].y))>>1;
00428                         pPolyCordBuffer[CurrentPolyIndex+2].y=SCALEY(CurrentY);
00429                     }
00430 
00431                     pPolyCordBuffer[CurrentPolyIndex+1].x=
00432 // This can overflow - best to scale the components separately
00433 //                  SCALEX((CurrentX+((FIXEDTOINT32(pPolyCurve->apfx[i].x))<<1))/3);
00434                     SCALEX(CurrentX/3) + SCALEX(((FIXEDTOINT32(pPolyCurve->apfx[i].x))<<1)/3);
00435                     
00436                     pPolyCordBuffer[CurrentPolyIndex+1].y=
00437 // This can overflow - best to scale the components separately
00438 //                  SCALEY((CurrentY+((FIXEDTOINT32(pPolyCurve->apfx[i].y))<<1))/3);
00439                     SCALEY(CurrentY/3) + SCALEY(((FIXEDTOINT32(pPolyCurve->apfx[i].y))<<1)/3);
00440                     
00441                     CurrentPolyIndex=CurrentPolyIndex+3;
00442 
00443                 }
00444                 break;
00445                 
00446                 default:
00447                 delete[] pGlyphBuffer;
00448                 TRACE( _T("oh my god\n"));
00449                 AfxThrowMemoryException();
00450             }
00451 
00452             pPosInGlyphBuffer=pPosInGlyphBuffer+sizeof(TTPOLYCURVE)+(NoOfArrayElements-1)*sizeof(POINTFX);
00453 
00454         } while (pPosInGlyphBuffer<(BYTE*)pPolyHeader+ContourSize);
00455         
00456         if ( (pPolyCordBuffer[FirstContourIndex].x != pPolyCordBuffer[CurrentPolyIndex-1].x) ||
00457                  (pPolyCordBuffer[FirstContourIndex].y != pPolyCordBuffer[CurrentPolyIndex-1].y))
00458         {
00459             pPolyVerbBuffer[CurrentPolyIndex]=PT_LINETO | PT_CLOSEFIGURE;
00460             pPolyCordBuffer[CurrentPolyIndex]=pPolyCordBuffer[FirstContourIndex];
00461             CurrentPolyIndex++;
00462         }
00463         else 
00464         {
00465             pPolyVerbBuffer[CurrentPolyIndex-1]=pPolyVerbBuffer[CurrentPolyIndex-1] | PT_CLOSEFIGURE;
00466         }
00467 
00468     }       
00469     delete[] pGlyphBuffer;
00470 
00471     *NoPolyElements=CurrentPolyIndex;
00472     return TRUE; 
00473 #else
00474     return FALSE;
00475 #endif
00476 }
00477 
00478 
00479 /*********************************************************************************************
00480 >   static INT32 TextManager::GetDesignSize(wxDC* pDC)
00481 
00482     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00483     Created:    12/1/96
00484     Inputs:     pDC - ptr to DC with font selected, for which design size required
00485     Returns:    design size of font in logical units (or -1 if fails)
00486     Note:       >>>> just returns a constant for the moment, but gives reasonable accuracy <<<<
00487 ********************************************************************************************/
00488 
00489 INT32 TextManager::GetDesignSize(wxDC* pDC)
00490 {
00491 //  ERROR2IF(pDC==NULL,FALSE,"TextManager::GetDesignSize() - pDC==NULL");
00492 
00493     return 2048;
00494 }
00495 
00496 
00497 /**********************************************************************************************
00498 >   static BOOL TextManager::GetLogFontFromCharDescriptor(wxDC* pDC, CharDescription& ChDesc,
00499                         LPLOGFONT pLogFont, INT32 LogicalHeight=-1)
00500 
00501     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00502     Created:    12/1/96
00503     Inputs:     pDC           - ptr to DC
00504                 ChDesc        - CharDescription containing font handle, bold, italic
00505                 LogicalHeight - desired height in DC pixels (or -1 for dpi - ie 1" high)
00506     Outputs:    pLogFont      - Logfont corresponding to given ChDesc at specified height
00507     Returns:    FALSE if fails
00508     Purpose:    Given a char descriptor, get its corresponding Logfont, and Font metrics if required
00509     Note:       Assumes MM_TextMode 
00510 *********************************************************************************************/
00511 
00512 BOOL TextManager::GetLogFontFromCharDescriptor(wxDC* pDC, CharDescription& ChDesc,
00513                                                LOGFONT* pLogFont, INT32 LogicalHeight)
00514 {
00515     ERROR2IF(pLogFont==NULL,FALSE,"TextManager::GetLogFontFromCharDescriptor() pLogFont==NULL");
00516     ERROR2IF(     pDC==NULL,FALSE,"TextManager::GetLogFontFromCharDescriptor() pDC==NULL");
00517 
00518     // get LogFont from face handle in char descriptor
00519     WORD            FaceHandle    = ChDesc.GetTypefaceHandle();
00520     CachedFontItem* pFontDataItem = FONTMANAGER->GetFont(FaceHandle);
00521     if (pFontDataItem == NULL) return FALSE;
00522 
00523     ENUMLOGFONT*    pEnumLogFont     = pFontDataItem->GetEnumLogFont();
00524     if (pEnumLogFont == NULL) return FALSE;
00525     *pLogFont = pEnumLogFont->elfLogFont;
00526 
00527 #ifndef EXCLUDE_FROM_XARALX
00528     // if not specified, set LogicalHeight to dpi (ie 1")
00529     if (LogicalHeight==-1)
00530         LogicalHeight = pDC->GetDeviceCaps(LOGPIXELSY);
00531 
00532     // set font height, aspect (100%), bold, italic
00533     pLogFont->lfHeight = -LogicalHeight;
00534     pLogFont->lfWidth  = 0;
00535     pLogFont->lfWeight = ChDesc.GetBold() ? 700 : 0; 
00536     pLogFont->lfItalic = ChDesc.GetItalic();
00537 #else
00538     ERROR2IF(LogicalHeight==-1, FALSE, "NYI - get device DPI");
00539 #endif
00540 
00541     return TRUE;
00542 }
00543 
00544 
00545 /********************************************************************************************
00546 >   static BOOL TextManager::GetInfoFromLogFont(FontInfo* pFontInfo, LOGFONT* pLogFont,
00547                                                                  FontClass Class = FC_UNDEFINED);
00548     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00549     Created:    8/4/95
00550     Inputs:     pLogFont  - Log font to obtain info from
00551                 Class     - describes the type of class (see typedef for details)
00552                             FC_UNDEFINED then ignore the class match and match the first
00553                             item with the same name whatever font class it is
00554     Outputs:    pFontInfo - Fontinfo structure built from given log font
00555     Returns:    FALSE if fails
00556     Purpose:    extract as many text attributes as possible from a LOGFONT structure
00557     Note:       assumes the font is cached
00558 ********************************************************************************************/
00559 
00560 BOOL TextManager::GetInfoFromLogFont(FontInfo* pFontInfo, LOGFONT* pLogFont, FontClass Class)
00561 {
00562 #ifndef EXCLUDE_FROM_XARALX
00563 // BODGE TEXT - no error trapping of creating new MFC objects - TRY/THROW required
00564 
00565     // ensure the font is cached
00566     String_64 Desc(pLogFont->lfFaceName);
00567     if (FONTMANAGER->CacheNamedFont(&Desc, Class)==ILLEGALFHANDLE)
00568         return FALSE;
00569 
00570     // create DC and get it's pixels per inch
00571     CDC ADC;
00572     if (ADC.CreateCompatibleDC(NULL)==0)
00573         ERROR2(FALSE,"TextManager::GetInfoFromLogFont() - CreateCompatibleDC() failed");
00574     INT32 PixelsPerInch=ADC.GetDeviceCaps(LOGPIXELSX);
00575     if (PixelsPerInch==0)
00576         ERROR2(FALSE,"TextManager::GetInfoFromLogFont() - GetDeviceCaps() failed");
00577 
00578     // create a font from the LOGFONT but of default width
00579     INT32 DefaultAveCharWidth=0;
00580     if (pLogFont->lfWidth!=0)
00581     {
00582         LOGFONT DefaultWidthLogFont=*pLogFont;
00583         DefaultWidthLogFont.lfWidth=0;
00584         CFont DefaultWidthFont;
00585         if (DefaultWidthFont.CreateFontIndirect(&DefaultWidthLogFont)==0)
00586             ERROR2(FALSE,"TextManager::GetInfoFromLogFont() - CreateFontIndirect() failed");
00587         CFont* pOldFont=ADC.SelectObject(&DefaultWidthFont);
00588         ERROR2IF(pOldFont==NULL,FALSE,"TextManager::GetInfoFromLogFont() - SelectObject() failed");
00589         TEXTMETRIC TM;
00590         if (ADC.GetTextMetrics(&TM)==0)
00591             ERROR2(FALSE,"TextManager::GetInfoFromLogFont() - GetTextMetrics() failed");
00592         DefaultAveCharWidth=TM.tmAveCharWidth;
00593         if (ADC.SelectObject(pOldFont)==NULL)
00594             ERROR2(FALSE,"TextManager::GetInfoFromLogFont() - SelectObject() failed");
00595     }
00596 
00597     // create font from LOGFONT, select it into DC, and get metrics
00598     CFont font;
00599     if (font.CreateFontIndirect(pLogFont)==0)
00600         ERROR2(FALSE,"TextManager::GetInfoFromLogFont() - CreateFontIndirect() failed");
00601     CFont* pOldFont=ADC.SelectObject(&font);
00602     ERROR2IF(pOldFont==NULL,FALSE,"TextManager::GetInfoFromLogFont() - SelectObject() failed");
00603     TEXTMETRIC TM;
00604     if (ADC.GetTextMetrics(&TM)==0)
00605         ERROR2(FALSE,"TextManager::GetInfoFromLogFont() - GetTextMetrics() failed");
00606     if (ADC.SelectObject(pOldFont)==NULL)
00607         ERROR2(FALSE,"TextManager::GetInfoFromLogFont() - SelectObject() failed");
00608 
00609     MILLIPOINT FontSize = MulDiv(TM.tmHeight-TM.tmInternalLeading,72000,PixelsPerInch);
00610     ERROR2IF(FontSize==-1,FALSE,"TextManager::GetInfoFromLogFont() - MulDiv() failed");
00611     FIXED16 FontAspect = DefaultAveCharWidth!=0 ? Div32By32(TM.tmAveCharWidth,DefaultAveCharWidth) : 1;
00612     ERROR2IF(FontAspect==-1,FALSE,"TextManager::GetInfoFromLogFont() - MulDiv() failed");
00613 
00614     pFontInfo->Handle   = FONTMANAGER->GetFontHandle(&Desc, Class);
00615     pFontInfo->Size     = FontSize;
00616     pFontInfo->Aspect   = FontAspect;
00617     pFontInfo->Bold     = pLogFont->lfWeight >  FW_MEDIUM;
00618     pFontInfo->Italic   = pLogFont->lfItalic != FALSE;
00619     pFontInfo->Rotation = pLogFont->lfEscapement / 10.0;
00620 
00621     return TRUE;
00622 #else
00623     return FALSE;
00624 #endif
00625 }
00626 
00627 
00628 /********************************************************************************************
00629 >   static CharCase TextManager::ProcessCharCase(WCHAR* pChar, CharCase NewState)
00630 
00631     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00632     Created:    6/4/95
00633     Inputs:     pChar - pointer to char to process
00634                 NewState - Upper/Lower/Swap/Read
00635     Ouptuts:    pChar - modified char (if required)
00636     Returns:    previous state of char (Upper/Lower/Unknown) or Failed
00637     Purpose:    process the case of a char (accounting for Unicode and non-unicode builds!)
00638 ********************************************************************************************/
00639 
00640 CharCase TextManager::ProcessCharCase(WCHAR* pChar, CharCase NewState)
00641 {
00642     ERROR2IF(pChar==NULL,Failed,"TextManager::ProcessCharCase() - pChar==NULL");
00643     ERROR2IF(NewState==Failed || NewState==UnknownType,Failed,"TextManager::ProcessCharCase() - invalid NewState");
00644     ERROR2IF(sizeof(TCHAR) != sizeof(WCHAR), Failed,"TextManager::ProcessCharCase - Unicode only");
00645 
00646     CharCase OldCase=UnknownType;
00647 
00648     // get a lower case version of the char (if it changes it must have been upper)
00649     WCHAR OldCharW = *pChar;
00650     WCHAR LowerCharW = OldCharW;
00651     if ((WCHAR)camTolower(OldCharW) != OldCharW)
00652     {
00653         OldCase = Upper;
00654         LowerCharW = camTolower(OldCharW);
00655     }
00656 
00657     // get an upper case version of the char (if it changes it must have been lower)
00658     WCHAR UpperCharW = OldCharW;
00659     if ((WCHAR)camToupper(OldCharW) != OldCharW)
00660     {
00661         OldCase = Lower;
00662         UpperCharW = camToupper(OldCharW);
00663     }
00664 
00665     // if its case can be changed and we want to change it do it!
00666     if (OldCase!=UnknownType && NewState!=Read)
00667     {
00668         if (NewState==Swap)
00669             NewState = OldCase==Lower ? Upper : Lower;
00670         WCHAR NewChar = NewState==Lower ? LowerCharW : UpperCharW;
00671         *pChar = NewChar;
00672     }
00673 
00674     return OldCase;
00675 }
00676 
00677 
00678 
00679 /********************************************************************************************
00680 >   BOOL TextManager::GetCharWidth(wxDC* pDC, WCHAR FirstChar, WCHAR, LastChar, INT32* pCharWidthsBuf)
00681 
00682     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00683     Created:    12/1/96
00684     Inputs:     pDC                 - pointer to DC with correct font selected
00685                 FirstChar, LastChar - range of chars for which char widths required
00686     Outputs:    pCharWidthsBuf      - buffer filled with char widths
00687     Returns:    FALSE if fails
00688     Purpose:    Interface to API call, dynamically accounting for Unicode ability of OS
00689     Note:       pCharWidthsBuf size must be LastChar-FirstChar+1
00690 ********************************************************************************************/
00691 
00692 BOOL TextManager::GetCharWidth(wxDC* pDC, WCHAR FirstChar, WCHAR LastChar, INT32* pCharWidthsBuf)
00693 {
00694 #ifndef EXCLUDE_FROM_XARALX
00695     ERROR2IF(           pDC==NULL,FALSE,"TextManager::GetCharWidth() - pDC==NULL");
00696     ERROR2IF(pCharWidthsBuf==NULL,FALSE,"TextManager::GetCharWidth() - pCharWidthsBuf==NULL");
00697 
00698     BOOL ok=TRUE;
00699     if (UnicodeManager::IsUnicodeCompleteOS())
00700         ok = ::GetCharWidthW(pDC->GetSafeHdc(), FirstChar, LastChar, pCharWidthsBuf);
00701     else
00702     {
00703         UINT32 FirstMBChar = UnicodeManager::UnicodeToMultiByte(FirstChar);
00704         UINT32 LastMBChar  = UnicodeManager::UnicodeToMultiByte(LastChar);
00705         ok = ::GetCharWidthA(pDC->GetSafeHdc(), FirstMBChar, LastMBChar, pCharWidthsBuf);
00706     }
00707 
00708     ERROR2IF(!ok,FALSE,"TextManager::GetCharWidth() - ::GetCharWidth() failed");
00709 
00710     return TRUE;
00711 #else
00712     return FALSE;
00713 #endif
00714 }
00715 
00716 
00717 /********************************************************************************************
00718 >   BOOL TextManager::GetCharABCWidths(wxDC* pDC, WCHAR FirstChar, WCHAR, LastChar, INT32* pCharABCsBuf)
00719 
00720     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00721     Created:    12/1/96
00722     Inputs:     pDC                 - pointer to DC with correct font selected
00723                 FirstChar, LastChar - range of chars for which char ABC widths required
00724     Outputs:    pCharABCsBuf   - buffer filled with char ABC widths
00725     Returns:    FALSE if fails
00726     Purpose:    Interface to API call, dynamically accounting for Unicode ability of OS
00727     Note:       pABCWidthsBuf size must be LastChar-FirstChar+1
00728 ********************************************************************************************/
00729 
00730 BOOL TextManager::GetCharABCWidths(wxDC* pDC, WCHAR FirstChar, WCHAR LastChar, ABC* pCharABCsBuf)
00731 {
00732 #ifndef EXCLUDE_FROM_XARALX
00733     ERROR2IF(              pDC==NULL,FALSE,"TextManager::GetABCWidths() - pDC==NULL");
00734     ERROR2IF(pCharABCsBuf==NULL,FALSE,"TextManager::GetABCWidths() - pCharABCsBuf==NULL");
00735 
00736     BOOL ok=TRUE;
00737     if (UnicodeManager::IsUnicodeCompleteOS())
00738         ok = ::GetCharABCWidthsW(pDC->GetSafeHdc(), FirstChar, LastChar, pCharABCsBuf);
00739     else
00740     {
00741         UINT32 FirstMBChar = UnicodeManager::UnicodeToMultiByte(FirstChar);
00742         UINT32 LastMBChar  = UnicodeManager::UnicodeToMultiByte(LastChar);
00743         ok = ::GetCharABCWidthsA(pDC->GetSafeHdc(), FirstMBChar, LastMBChar, pCharABCsBuf);
00744     }
00745 
00746     ERROR2IF(!ok,FALSE,"TextManager::GetABCWidths() - ::GetCharABCWidths() failed");
00747 
00748     return TRUE;
00749 #else
00750     return FALSE;
00751 #endif
00752 }
00753 
00754 
00755 /********************************************************************************************
00756 
00757 >   INT32   TextManager::GetKernCount(wxDC* pDC)
00758 
00759     Author:     Jonathan_Payne (Xara Group Ltd) <camelotdev@xara.com>
00760     Created:    16/10/2000
00761     Inputs:     pDC             - DC with currently selected font
00762     Returns:    Number of kerns (0 if there are no kerns or there is an error)
00763     Purpose:    Find the number of kerns for the currently selected font
00764     See also:   TextManager::FillKernArray()
00765 
00766 ********************************************************************************************/
00767 INT32 TextManager::GetKernCount(wxDC* pDC)
00768 {
00769     ERROR2IF(pDC==0,0,"TextManager::GetKernCount() passed null DC");
00770 #ifndef EXCLUDE_FROM_XARALX
00771     return pDC->GetKerningPairs(0, 0);
00772 #else
00773     return 0;
00774 #endif
00775 }
00776 
00777 
00778 
00779 /********************************************************************************************
00780 
00781 >   bool TextManager::FillKernArray(wxDC* pDC, KERNINGPAIR *pKerningPairs, INT32 count)
00782 
00783     Author:     Jonathan_Payne (Xara Group Ltd) <camelotdev@xara.com>
00784     Created:    16/10/2000
00785     Inputs:     pDC             - DC with currently selected font
00786                 count           - Size of the array (must be >= GetKernCount() )
00787     Outputs     pKerningPairs   - Pointer to an array to fill with the kerning pairs
00788     Returns:    true if all is OK or false if things go real bad
00789     Purpose:    Fills an array with kerning data for the currently selected font    
00790     See also:   TextManager::GetKernCount()
00791 
00792 ********************************************************************************************/
00793 bool TextManager::FillKernArray(wxDC* pDC, MillipointKerningPair* pKerningPairs, INT32 count)
00794 {
00795     ERROR2IF(pDC==0, 0,                 "TextManager::FillKernArray() passed null DC");
00796     ERROR3IF(count<GetKernCount(pDC),   "TextManager::FillKernArray() not passed enough memory - "
00797                                         "kern table will be incomplete");
00798 #ifndef EXCLUDE_FROM_XARALX
00799     // Allocate some tmp memory to store windows kerning data
00800     KERNINGPAIR* pKPtmp = new KERNINGPAIR[count];
00801     if (!pKPtmp) return false;
00802 
00803     // Get windows kerning data
00804     INT32 number = pDC->GetKerningPairs(count, pKPtmp);
00805 
00806     // Convert windows data into our own format
00807     for (INT32 c = 0; c < number; ++c)
00808     {
00809         pKerningPairs[c].wFirst         = pKPtmp[c].wFirst;
00810         pKerningPairs[c].wSecond        = pKPtmp[c].wSecond;
00811         pKerningPairs[c].iKernAmount    = pKPtmp[c].iKernAmount;
00812     }
00813     
00814     // Delete tmp memory
00815     delete pKPtmp;
00816 
00817     // Check for error condition
00818     if (number == 0 && GetKernCount(pDC) != 0)
00819     {
00820         ERROR3("Error reading kerning data");
00821         return false;
00822     }
00823     else
00824     {
00825         return true;
00826     }
00827 #else
00828     return FALSE;
00829 #endif
00830 }

Generated on Sat Nov 10 03:48:57 2007 for Camelot by  doxygen 1.4.4