cdrtext.cpp

Go to the documentation of this file.
00001 // $Id: cdrtext.cpp 1282 2006-06-09 09:46:49Z 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 // ********* Text objects for CDR files
00099 
00100 /*
00101 */
00102 
00103 #include "camtypes.h"
00104 #include "cdrfiltr.h"
00105 #include "nodetxts.h"
00106 #include "nodetxtl.h"
00107 #include "nodetext.h"
00108 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 //#include "txtattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00111 #include "fontman.h"
00112 
00113 DECLARE_SOURCE("$Revision: 1282 $");
00114 
00115 #define new CAM_DEBUG_NEW
00116 
00117 static TCHAR *CDRDefaultFontName = "AvantGarde Bk BT";
00118 static CDRTextStyle CDRDefaultTextStyle = {0, (72000*24)/72, FALSE, FALSE, FALSE, CDRSCRIPT_NONE,
00119             (1000*24)/72, 100, JLEFT};
00120 
00121 /********************************************************************************************
00122 
00123 >   BOOL CDRFilter::ConvertText(cdrfOffsetHeader *Header)
00124 
00125     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00126     Created:    24 03 95
00127     Inputs:     none
00128     Returns:    error flag
00129     Purpose:    converts a text object to a node. If the object has an unexpected
00130                 format, then FormatError is set and it return *TRUE* - the return value only
00131                 indicated environmental errors such as lack of memory
00132     SeeAlso:    
00133 
00134 ********************************************************************************************/
00135 
00136 BOOL CDRFilter::ConvertText(cdrfOffsetHeader *Header)
00137 {
00138     // check to see if this has an offset for text on a path
00139     if(FindDataInObject(Header, cdrfOBJOFFSETTYPE_PATHTEXT1) != 0
00140             && FindDataInObject(Header, cdrfOBJOFFSETTYPE_PATHTEXT2) != 0)
00141     {
00142         IsTextOnAPath = TRUE;
00143     }
00144     else
00145     {
00146         IsTextOnAPath = FALSE;
00147     }
00148 
00149     // hey, this is text!
00150     IsText = TRUE;
00151     IsTextStory = FALSE;
00152 
00153     // dispatch conversion to appropriate routine
00154     if(Version == CDRVERSION_3)
00155         return ConvertText3(Header);
00156 
00157     if(Version == CDRVERSION_4)
00158     {
00159         if(CDRDATA_WORD(Header->ObjectType) == cdrfOBJTYPE_TEXT)
00160         {
00161             return ConvertText4Art(Header);
00162         }
00163         else
00164         {
00165             return ConvertText4Para(Header);
00166         }
00167     }
00168 
00169     // if it's a text story we're fiddling with, see how big the frame is
00170     INT32 FrameX = 0, FrameY = 0;
00171     DocCoord Trans = DocCoord(0,0);
00172     if(Header->ObjectType == cdrfOBJTYPE_TEXTSTORY)
00173     {
00174         // find the size of the object
00175         cdrfTextStoryCoordData *Coords = (cdrfTextStoryCoordData *)FindDataInObject(Header, cdrfOBJOFFSETTYPE_COORDS);
00176     
00177         if(Coords == 0)
00178         {
00179             FormatError = TRUE;
00180             return TRUE;
00181         }
00182 
00183         FrameX = CDRDATA_WORD(Coords->XSize);
00184         FrameY = CDRDATA_WORD(Coords->YSize);
00185 TRACEUSER( "Ben", _T("Initial frame dimensions: X = %d Y = %d\n"), FrameX, FrameY);
00186 
00187         IsTextStory = TRUE;
00188     }
00189     else
00190     {
00191         IsTextStory = FALSE;
00192     }
00193 
00194     // OK, the header supplied here is in a block of it's own so we can aquire a new RIFF block
00195     // for the text info
00196 
00197     // the RIFF object will be at a loda chunk, which is at a one higher level than that of
00198     // the txsm chunk - find level we don't want to seek over
00199     ERROR3IF(RIFF->GetObjType() != RIFFOBJECTTYPE_CHUNK || RIFF->GetObjChunkType() != cdrT_loda,
00200         "CDFFilter::ConvertText called with RIFF on a non-loda chunk");
00201     UINT32 EndLevel = RIFF->GetObjLevel() - 1;
00202 
00203     // now stroll though the RIFF file
00204     // stop when we find a txsm chunk, and store any trfd chunks we might meet on the way
00205     BOOL Found = FALSE;
00206     do
00207     {
00208         if(RIFF->GetObjType() == RIFFOBJECTTYPE_CHUNK && RIFF->GetObjChunkType() == cdrT_txsm)
00209         {
00210             // found the text info thingy
00211             Found = TRUE;
00212         }
00213         else if(RIFF->GetObjType() == RIFFOBJECTTYPE_LISTSTART && RIFF->GetObjChunkType() == cdrT_trfl)
00214         {
00215             // grab the list contents
00216             if(!RIFF->GetListContents(&TransformChunk, &TransformChunkSize))
00217                 return FALSE;
00218         }
00219 
00220         UpdateProgress();
00221 
00222         if(!Found)
00223             if(!RIFF->NextObject())
00224                 return FALSE;
00225     
00226     } while(Found == FALSE && (RIFF->GetObjType() != RIFFOBJECTTYPE_LISTEND || RIFF->GetObjLevel() >= EndLevel));
00227 
00228     if(RIFF->GetObjType() != RIFFOBJECTTYPE_CHUNK || RIFF->GetObjChunkType() != cdrT_txsm)
00229     {
00230         FormatError = TRUE;
00231         return TRUE;
00232     }
00233 
00234     // get size of chunk
00235     INT32 TextInfoSize = RIFF->GetObjSize();
00236     
00237     // aquire the chunk data
00238     if(!RIFF->AquireChunkData())
00239         return FALSE;
00240 
00241     // and get a pointer to the 'nice' info chunk
00242     ADDR TextInfo;
00243     if((TextInfo = RIFF->GetAquiredData()) == 0)
00244     {
00245         return FALSE;
00246     }
00247     cdrfTextInfoHdr *TIH = (cdrfTextInfoHdr *)TextInfo;
00248 
00249     // make a new text story node
00250     TextStory *TSNode = new TextStory;
00251 
00252     if(TSNode == 0)
00253         return FALSE;
00254     
00255     // get the number of paragraphs
00256     UINT32 NParagraphs = CDRDATA_WORD(TIH->NParagraphs);
00257 
00258     // set up some variables
00259     INT32 Loc = sizeof(cdrfTextInfoHdr);
00260     INT32 FirstLineSpace = -1;
00261     INT32 InitialFirstLineSpace = -1;
00262     INT32 ThisLineSpace = 0;
00263     INT32 PreviousLineSpace = 0;
00264     INT32 MaximumLineX = 0;     // MaximumLineX and
00265     INT32 Lines = 1;                // Lines only used for artisitic text
00266     Justification Just;         // the justification
00267 
00268     // convert the paragraph
00269     UINT32 CurrentPara;
00270     INT32 LineX;
00271     for(CurrentPara = 0; CurrentPara < NParagraphs; CurrentPara++)
00272     {
00273         // set up a few things
00274         LineX = 0;          // current position in the line
00275         
00276         // check sizes
00277         if((Loc + (INT32)sizeof(cdrfTextInfoParaHdr)) > TextInfoSize)
00278             break;
00279     
00280         // get paragraph header info
00281         cdrfTextInfoParaHdr *ParaHdr = (cdrfTextInfoParaHdr *)(TextInfo + Loc);
00282         Loc += sizeof(cdrfTextInfoParaHdr);
00283 
00284         // sort out font style definitions
00285         INT32 NFontDefns = CDRDATA_WORD(ParaHdr->NFontDefns);
00286 
00287         if((Loc + ((INT32)sizeof(cdrfTextInfoFontDefn) * NFontDefns)) > TextInfoSize)
00288             break;
00289     
00290         cdrfTextInfoFontDefn *FontDefns = (cdrfTextInfoFontDefn *)(TextInfo + Loc);
00291         Loc += (sizeof(cdrfTextInfoFontDefn) * NFontDefns);
00292 
00293         // get some memory for the converted font styles
00294         if(NFontDefns <= 0)
00295             break;
00296 
00297         CDRTextStyle *Styles = new CDRTextStyle[NFontDefns];
00298         
00299         // convert the first definiton from the style
00300         if(!GetTextStyleFromCDRStyle(&Styles[0], ParaHdr->Style))
00301             goto NoMemory;
00302 
00303         // store the justificationness
00304         Just = Styles[0].Just;
00305 
00306         // just in case of random Corel behaviour...
00307         PreviousLineSpace = (Styles[0].FontSize * 12) / 10;
00308 
00309         // go through translating all the other styles
00310         for(INT32 l = 1; l < NFontDefns; l++)
00311         {
00312             if(!GetTextStyleFromDefn(&Styles[l], &FontDefns[l], &Styles[0]))
00313                 return FALSE;
00314         }
00315 
00316         // get the paragraph info
00317         if((Loc + (INT32)sizeof(cdrfTextInfoParaInfo)) > TextInfoSize)
00318             break;
00319         
00320         cdrfTextInfoParaInfo *PInfo = (cdrfTextInfoParaInfo *)(TextInfo + Loc);
00321 
00322         Loc += sizeof(cdrfTextInfoParaInfo);
00323         
00324         INT32 NChars = CDRDATA_WORD(PInfo->NChars);
00325 
00326         // sort out the character array
00327         if((Loc + ((INT32)sizeof(cdrfTextInfoChar) * NChars)) > TextInfoSize)
00328             break;
00329         
00330         cdrfTextInfoChar *Chars = (cdrfTextInfoChar *)(TextInfo + Loc);
00331 
00332         Loc += (sizeof(cdrfTextInfoChar) * NChars);
00333     
00334         // make a new text line for this paragraph
00335         TextLine *CurrentLine = new TextLine(TSNode, LASTCHILD);
00336         if(CurrentLine == 0)
00337             goto NoMemory;
00338 
00339         // and run through adding all those nice characters
00340         INT32 CurrentChar;
00341         for(CurrentChar = 0; CurrentChar < NChars; CurrentChar++)
00342         {
00343             BOOL NewLine = FALSE;       // whether to create a new line here
00344 
00345             if(IsTextStory == FALSE && CDRDATA_WORD(Chars[CurrentChar].Code) == cdrfTEXT_NEWLINE)
00346             {
00347                 // update a couple of artisitic text only variables
00348                 Lines++;
00349 
00350                 if(LineX > MaximumLineX)
00351                     MaximumLineX = LineX;
00352 
00353                 // create a new line
00354                 NewLine = TRUE;
00355             }
00356             
00357             // find the style of the character
00358             INT32 Style = ((CDRDATA_WORD(Chars[CurrentChar].Info)) & cdrfTEXTINFOCHAR_INFO_DEFNMASK)
00359                         >> cdrfTEXTINFOCHAR_INFO_DEFNMASKSBY;
00360 
00361             // create it
00362             if(CDRDATA_WORD(Chars[CurrentChar].Code) >= ' ')
00363             {
00364                 TextChar *C = new TextChar(CurrentLine, LASTCHILD, CDRDATA_WORD(Chars[CurrentChar].Code));
00365 
00366                 if(C == 0)
00367                     goto NoMemory;
00368 
00369                 if(Style < 0 || Style >= NFontDefns)
00370                     Style = 0;
00371 
00372                 // apply attributes
00373                 if(!ApplyTextAttr(C, &Styles[Style], 0 /*&Styles[0]*/))     // for now, we can't base attributes on anything 'cos the optimiser can't hack it
00374                     goto NoMemory;
00375             }
00376 
00377             // add the character width
00378             LineX += CDRDATA_SWORD(Chars[CurrentChar].XSize);
00379 
00380             // update this line's spacing thingy
00381             if(Styles[Style].LineSpace > ThisLineSpace)
00382                 ThisLineSpace = Styles[Style].LineSpace;
00383 
00384             // sort out first line spaceing thing
00385             if(InitialFirstLineSpace == -1)
00386                 InitialFirstLineSpace = Styles[Style].LineSpace;
00387 
00388             if(NewLine)
00389             {
00390                 // apply the line spacing attribute - make a font size attribute
00391                 if(ThisLineSpace < 512)
00392                     ThisLineSpace = PreviousLineSpace;
00393                 TxtLineSpaceAttribute Attr((FIXED16)(((double)Styles[0].ParaLineSpacePercent) /* * 1.2*/ / 100));
00394 
00395                 // attach
00396                 if(!ApplyTextAttrDoApply(CurrentLine, &Attr, FALSE))
00397                     return FALSE;
00398 
00399                 // add an EOL
00400                 EOLNode *EOL = new EOLNode(CurrentLine, LASTCHILD);
00401                 if(EOL == 0)
00402                     goto NoMemory;
00403                 // make a new line
00404                 CurrentLine = new TextLine(TSNode, LASTCHILD);
00405                 if(CurrentLine == 0)
00406                     goto NoMemory;
00407 
00408                 // sort out first line spacing thing
00409                 if(FirstLineSpace == -1)
00410                     FirstLineSpace = ThisLineSpace;
00411 
00412                 // reset things
00413                 LineX = 0;
00414                 PreviousLineSpace = ThisLineSpace;
00415                 ThisLineSpace = 0;
00416             }
00417         }
00418 
00419         // sort out first line spaceing thing
00420         if(FirstLineSpace == -1)
00421             FirstLineSpace = ThisLineSpace;
00422 
00423         // apply the line spacing attribute - make a font size attribute
00424         if(ThisLineSpace < 512)
00425             ThisLineSpace = PreviousLineSpace;
00426         TxtLineSpaceAttribute Attr((FIXED16)(((double)Styles[0].ParaLineSpacePercent)  / 100));
00427     
00428         // attach
00429         if(!ApplyTextAttrDoApply(CurrentLine, &Attr, FALSE))
00430             return FALSE;
00431 
00432         // pop on an end of line node
00433         EOLNode *EOL = new EOLNode(CurrentLine, LASTCHILD);
00434 
00435         if(EOL == 0)
00436             goto NoMemory;
00437 
00438         // get rid of the font styles
00439         delete [] Styles;
00440 
00441         PreviousLineSpace = ThisLineSpace;
00442     }
00443 
00444     // pop a caret at the end of the last line
00445     {
00446         Node *LastLine = TSNode->FindLastChild();
00447 
00448         if(LastLine == 0)
00449             goto FormError;
00450 
00451         Node *LastLineNode = LastLine->FindLastChild();
00452 
00453         ERROR3IF(LastLineNode == 0, "Line node doesn't have any children");
00454         ERROR3IF(!LastLineNode->IsKindOf(CC_RUNTIME_CLASS(EOLNode)), "Last entry of a line is not an EOL node");
00455         
00456         CaretNode *C = new CaretNode(LastLineNode, PREV);
00457         if(C == 0)
00458             goto NoMemory;
00459     }
00460 
00461     // set up maximumlinex - only valid for artisitic text
00462     if(LineX > MaximumLineX)
00463         MaximumLineX = LineX;
00464 
00465     // set up a bounding box for this text object and
00466     // if this is a text story, translate it down a bit
00467     // so that the top of the first line is at the top of the frame
00468     if(IsTextStory)
00469     {
00470         if(FirstLineSpace == -1)
00471             goto FormError;         // no first line? How strange...
00472 
00473         // work out the distance to move the text line down = the first line un 120%ed
00474         INT32 Down = (FirstLineSpace * 10) / 12;
00475 
00476         // work out the rightness shifting
00477         INT32 Right = 0;
00478         if(Just == JCENTRE)
00479         {
00480             Right = (FrameX / 2) * CDRCOORDS_TO_MILLIPOINTS;
00481         }
00482         else if(Just == JRIGHT)
00483         {
00484             Right = FrameX * CDRCOORDS_TO_MILLIPOINTS;
00485         }
00486 
00487         // transform the story
00488         TSNode->SetStoryMatrix(Matrix(Trans.x+Right, Trans.y-Down));
00489 
00490         // set the format width
00491         TSNode->SetImportFormatWidth(FrameX * CDRCOORDS_TO_MILLIPOINTS);
00492 TRACEUSER( "Ben", _T("Import format width initially %d\n"), TSNode->GetImportFormatWidth());
00493 
00494         // bounding box for text story
00495         DocRect BBox = DocRect(Trans.x, Trans.y - (FrameY * CDRCOORDS_TO_MILLIPOINTS),
00496                 Trans.x + (FrameX * CDRCOORDS_TO_MILLIPOINTS), Trans.y);
00497 
00498         TextBBoxes.Add(TSNode, &BBox, JLEFT);
00499     }
00500     else
00501     {
00502         // set the matrix of the story
00503         TSNode->SetStoryMatrix(Matrix(0,0));
00504 
00505         // bounding box for a text object
00506         DocRect BBox = DocRect(0, 0 - FirstLineSpace * Lines,
00507                 (MaximumLineX * CDRCOORDS_TO_MILLIPOINTS), FirstLineSpace);
00508 
00509         TextBBoxes.Add(TSNode, &BBox, Just);
00510 
00511         // see if this is linked to a path
00512         CheckTextForLinks(TSNode, Header);
00513     }
00514 
00515     // set some essential variables
00516     ObjFilled = TRUE;
00517     ObjStroked = FALSE;
00518 
00519     // all done return...
00520     pMadeNode = TSNode;
00521 
00522     return TRUE;
00523 
00524 NoMemory:
00525     TSNode->CascadeDelete();
00526     delete TSNode;
00527     
00528     return FALSE;
00529 
00530 FormError:
00531     FormatError = TRUE;
00532     TSNode->CascadeDelete();
00533     delete TSNode;
00534     
00535     return TRUE;
00536 }
00537 
00538 
00539 /********************************************************************************************
00540 
00541 >   BOOL CDRFilter::ConvertText4Art(cdrfOffsetHeader *Header)
00542 
00543     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00544     Created:    24 03 95
00545     Inputs:     none
00546     Returns:    error flag
00547     Purpose:    converts a version 4 artisitic text object
00548     SeeAlso:    
00549 
00550 ********************************************************************************************/
00551 
00552 BOOL CDRFilter::ConvertText4Art(cdrfOffsetHeader *Header)
00553 {
00554     // get the data from this object
00555     cdrfTextHeaderV4 *Hdr = (cdrfTextHeaderV4 *)FindDataInObject(Header, cdrfOBJOFFSETTYPE_COORDS);
00556 
00557     // it has got some coords, hasn't it?
00558     if(Hdr == 0)
00559     {
00560         FormatError = TRUE;
00561         return TRUE;
00562     }
00563     // find pointer to the characters
00564     cdrfTextCharV4 *ThisChar = (cdrfTextCharV4 *)(Hdr + 1);
00565 
00566     // get the base style
00567     CDRTextStyle BaseStyle;
00568 
00569     WORD *StyleRef = (WORD *)FindDataInObject(Header, cdrfOBJOFFSETTYPE_STYLE);
00570     if(StyleRef == 0)
00571     {
00572         FormatError = TRUE;
00573         return TRUE;
00574     }
00575 
00576     if(!GetTextStyleFromCDRStyle(&BaseStyle, CDRDATA_WORD(*StyleRef)))
00577         return FALSE;
00578 
00579     // make a new text story node
00580     TextStory *TSNode = new TextStory;
00581 
00582     if(TSNode == 0)
00583         return FALSE;
00584 
00585     // run through the text...
00586     INT32 NChars = CDRDATA_WORD(Hdr->NCharacters);
00587     INT32 CurrentChar;
00588     INT32 MaximumLineSpace = BaseStyle.LineSpace;
00589     INT32 Lines = 1;
00590     INT32 Depth = 0;
00591 
00592     // make a new text line
00593     TextLine *CurrentLine = new TextLine(TSNode, LASTCHILD);
00594     if(CurrentLine == 0)
00595         goto NoMemory;
00596 
00597     for(CurrentChar = 0; CurrentChar < NChars; CurrentChar++)
00598     {
00599         BOOL HasStyles = FALSE;
00600 
00601         if(ThisChar->Info != 0)
00602             HasStyles = TRUE;
00603 
00604         if(ThisChar->Code >= ' ')
00605         {
00606             TextChar *C = new TextChar(CurrentLine, LASTCHILD, ThisChar->Code);
00607 
00608             if(C == 0)
00609                 goto NoMemory;
00610 
00611             // apply attributes
00612             if(HasStyles)
00613             {
00614                 // it's got styles of it's own, find and apply them
00615                 cdrfTextCharStyledV4 *SC = (cdrfTextCharStyledV4 *)ThisChar;
00616 
00617                 CDRTextStyle ThisStyle;
00618 
00619                 if(!GetTextStyleFromChar4(&ThisStyle, SC, &BaseStyle))
00620                     return FALSE;
00621 
00622                 if(!ApplyTextAttr(C, &ThisStyle, 0))
00623                     goto NoMemory;
00624         
00625                 if(ThisStyle.LineSpace > MaximumLineSpace)
00626                     MaximumLineSpace = ThisStyle.LineSpace;
00627             }
00628             else
00629             {
00630                 // just apply the normal attributes
00631                 if(!ApplyTextAttr(C, &BaseStyle, 0))
00632                     goto NoMemory;
00633             }
00634         }
00635 
00636         if(ThisChar->Code == cdrfTEXT_NEWLINE)
00637         {
00638             // create a new line...
00639             // apply the line spacing attribute - make a font size attribute
00640 //          TxtLineSpaceAttribute Attr(MaximumLineSpace);
00641             TxtLineSpaceAttribute Attr((FIXED16)(((double)BaseStyle.ParaLineSpacePercent)  / 100));
00642 
00643             // attach
00644             if(!ApplyTextAttrDoApply(CurrentLine, &Attr, FALSE))
00645                 return FALSE;
00646 
00647             // add an EOL
00648             EOLNode *EOL = new EOLNode(CurrentLine, LASTCHILD);
00649             if(EOL == 0)
00650                 goto NoMemory;
00651 
00652             // make a new line
00653             CurrentLine = new TextLine(TSNode, LASTCHILD);
00654             if(CurrentLine == 0)
00655                 goto NoMemory;
00656 
00657             // set things
00658             Lines++;
00659             Depth += MaximumLineSpace;
00660             MaximumLineSpace = BaseStyle.LineSpace;
00661         }
00662 
00663         if(HasStyles)
00664         {
00665             // it's got more than normal bytes in it, so add a few more than usual
00666             ThisChar = (cdrfTextCharV4 *)(((cdrfTextCharStyledV4 *)ThisChar) + 1);
00667         }
00668         else
00669         {
00670             // just a normal character, so simply increment it
00671             ThisChar++;
00672         }
00673     }
00674 
00675     // pop a line space attribute on the last line
00676     {
00677 //      TxtLineSpaceAttribute Attr(MaximumLineSpace);
00678         TxtLineSpaceAttribute Attr((FIXED16)(((double)BaseStyle.ParaLineSpacePercent)  / 100));
00679 
00680         // attach
00681         if(!ApplyTextAttrDoApply(CurrentLine, &Attr, FALSE))
00682             return FALSE;
00683     }
00684 
00685     Depth += MaximumLineSpace;
00686 
00687     // finish the last line with an end of line node
00688     {
00689         EOLNode *EOL = new EOLNode(CurrentLine, LASTCHILD);
00690 
00691         if(EOL == 0)
00692             goto NoMemory;
00693 
00694         // pop a caret at the end of the last line
00695         Node *LastLine = TSNode->FindLastChild();
00696 
00697         if(LastLine == 0)
00698             goto FormError;
00699 
00700         Node *LastLineNode = LastLine->FindLastChild();
00701 
00702         ERROR3IF(LastLineNode == 0, "Line node doesn't have any children");
00703         ERROR3IF(!LastLineNode->IsKindOf(CC_RUNTIME_CLASS(EOLNode)), "Last entry of a line is not an EOL node");
00704         
00705         CaretNode *C = new CaretNode(LastLineNode, PREV);
00706         if(C == 0)
00707             goto NoMemory;
00708     }
00709 
00710     // set the matrix of the story
00711     {
00712         TSNode->SetStoryMatrix(Matrix(0,0));
00713 
00714         // bounding box for a artisitic text object - approximate it's width
00715         INT32 Width = (MaximumLineSpace * NChars) / (Lines * 3);
00716 
00717         DocRect BBox = DocRect(0, 0 - Depth, Width, MaximumLineSpace);
00718 
00719         TextBBoxes.Add(TSNode, &BBox, BaseStyle.Just);
00720     }
00721 
00722     // check it for paths...
00723     CheckTextForLinks(TSNode, Header);
00724     
00725     // set some essential variables
00726     ObjFilled = TRUE;
00727     ObjStroked = FALSE;
00728     IsTextStory = FALSE;
00729 
00730     // all done, return...
00731     pMadeNode = TSNode;
00732 
00733     return TRUE;
00734 
00735 NoMemory:
00736     TSNode->CascadeDelete();
00737     delete TSNode;
00738     
00739     return FALSE;
00740 
00741 FormError:
00742     FormatError = TRUE;
00743     TSNode->CascadeDelete();
00744     delete TSNode;
00745     
00746     return TRUE;
00747 }
00748 
00749 
00750 /********************************************************************************************
00751 
00752 >   BOOL CDRFilter::ConvertText4Para(cdrfOffsetHeader *Header)
00753 
00754     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00755     Created:    24 03 95
00756     Inputs:     none
00757     Returns:    error flag
00758     Purpose:    converts a version 4 paragraph text object
00759     SeeAlso:    
00760 
00761 ********************************************************************************************/
00762 
00763 BOOL CDRFilter::ConvertText4Para(cdrfOffsetHeader *Header)
00764 {
00765     // get the data from this object
00766     cdrfParaTextHeaderV4 *Hdr = (cdrfParaTextHeaderV4 *)FindDataInObject(Header, cdrfOBJOFFSETTYPE_COORDS);
00767 
00768     // set the var...
00769     IsTextStory = TRUE;
00770 
00771     // it has got some coords, hasn't it?
00772     if(Hdr == 0)
00773     {
00774         FormatError = TRUE;
00775         return TRUE;
00776     }
00777 
00778 
00779     // find out what text item we need
00780     if(LinkTable == 0)
00781     {
00782         // no link table, oh dear
00783         FormatError = TRUE;
00784         return TRUE;
00785     }
00786 
00787     cdrfLinkTableHdr *th = (cdrfLinkTableHdr *)LinkTable;
00788 
00789     INT32 Entries = CDRDATA_WORD(th->Entries);
00790     BOOL Found = FALSE;
00791     WORD *Offsets = (WORD *)(LinkTable + CDRDATA_WORD(th->OffsetsOffset));
00792     cdrfLinkTableEntryTextV4 *En;
00793     for(INT32 l = 0; l < Entries; l++)
00794     {
00795         En = (cdrfLinkTableEntryTextV4 *)(LinkTable + CDRDATA_WORD(Offsets[l]));
00796     
00797         if(CDRDATA_WORD(En->Type) == cdrfLINKTABLEENTRYV4_TEXT &&
00798                 CDRDATA_WORD(En->ObjectSerial) == SerialNumber)
00799         {
00800             Found = TRUE;
00801             break;
00802         }
00803     }
00804 
00805     if(Found == FALSE)
00806     {
00807         FormatError = TRUE;
00808         return TRUE;
00809     }
00810     
00811     // locate the text item with those attributes
00812     CDRVectorStoredItem *Item = (CDRVectorStoredItem *)TextV4.GetHead();
00813     
00814     // go through the list of items searching for the reference number given
00815     while(Item != 0)
00816     {
00817         if(Item->Reference == CDRDATA_WORD(En->TextID))
00818         {
00819             // OK, we found it...
00820             break;
00821         }
00822 
00823         Item = (CDRVectorStoredItem *)TextV4.GetNext(Item);
00824     }
00825 
00826     if(Item == 0)
00827     {
00828         FormatError = TRUE;
00829         return TRUE;
00830     }
00831 
00832     Node *Text = Item->Objects;
00833 
00834     // find the base attributes
00835     CDRTextStyle BaseStyle;
00836 
00837     WORD *StyleRef = (WORD *)FindDataInObject(Header, cdrfOBJOFFSETTYPE_STYLE);
00838     if(StyleRef == 0)
00839     {
00840         FormatError = TRUE;
00841         return TRUE;
00842     }
00843 
00844     if(!GetTextStyleFromCDRStyle(&BaseStyle, CDRDATA_WORD(*StyleRef)))
00845         return FALSE;
00846     
00847     // get the maximum height of the first line
00848     ERROR2IF(!IS_A(Text, TextLine), FALSE, "Node in text list is not a text line");
00849 
00850     // apply attributes to the lines
00851     TextLine *CurrentLine = (TextLine *)Text;
00852     while(CurrentLine != 0)
00853     {
00854         if(IS_A(CurrentLine, TextLine))
00855         {
00856 /*          Node *pNode = CurrentLine->FindFirstChild();
00857 
00858             while(pNode != 0)
00859             {
00860                 if(IS_A(pNode, TextChar))
00861                 {
00862                     if(!ApplyTextAttr(pNode, &BaseStyle, 0))
00863                         return FALSE;
00864                 }
00865 
00866                 pNode = pNode->FindNext();
00867             }
00868 */
00869             // attach the line spacing onto it
00870             TxtLineSpaceAttribute Attr((FIXED16)(((double)BaseStyle.ParaLineSpacePercent)  / 100));
00871 
00872             if(!ApplyTextAttrDoApply(CurrentLine, &Attr, FALSE))
00873                 return FALSE;
00874         }
00875         
00876         CurrentLine = (TextLine *)CurrentLine->FindNext();
00877     }
00878 
00879     // add it to a text story
00880     TextStory *TSNode = new TextStory;
00881     if(TSNode == 0)
00882         return FALSE;
00883 
00884     Text->InsertChainSimple(TSNode, FIRSTCHILD);
00885 
00886     // remove references to the nodes now inserted from the item
00887     Item->Objects = 0;
00888 
00889     // set the matrix and add the bbox
00890     {
00891         INT32 FirstLineSpace = Item->BBox.hi.y;     // get the line spacing from the bbox defn
00892 
00893         // get the frame size
00894         INT32 FrameX = CDRDATA_WORD(Hdr->FrameX) * CDRCOORDS_TO_MILLIPOINTS;
00895         INT32 FrameY = CDRDATA_WORD(Hdr->FrameY) * CDRCOORDS_TO_MILLIPOINTS;
00896 
00897         // work out the distance to move the text line down = the first line un 120%ed
00898         INT32 Down = (FirstLineSpace * 10) / 12;
00899 
00900         // work out the shift...
00901         INT32 Right = 0;
00902         if(BaseStyle.Just == JCENTRE)
00903         {
00904             Right = FrameX / 2;
00905         }
00906         else if(BaseStyle.Just == JRIGHT)
00907         {
00908             Right = FrameX;
00909         }
00910 
00911         
00912         // transform the story
00913         TSNode->SetStoryMatrix(Matrix(Right,-Down));
00914 
00915         // bounding box for text story
00916         DocRect BBox = DocRect(0, 0 - FrameY, FrameX, 0);
00917 
00918         TextBBoxes.Add(TSNode, &BBox, JLEFT);
00919 
00920         // set it's width to be formatted to
00921         TSNode->SetImportFormatWidth(FrameX);
00922     }
00923 
00924     // delete the item
00925     delete TextV4.RemoveItem(Item);
00926 
00927     // set a few variables
00928     pMadeNode = TSNode;
00929     ObjFilled = TRUE;
00930     ObjStroked = FALSE;
00931 
00932     return TRUE;
00933 }
00934 
00935 
00936 /********************************************************************************************
00937 
00938 >   BOOL CDRFilter::GetTextStyleFromChar4(CDRTextStyle *TS, cdrfTextCharStyledV4 *Char, CDRTextStyle *BasedOn)
00939 
00940     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00941     Created:    24 03 95
00942     Inputs:     none
00943     Returns:    error flag
00944     Purpose:    gets a text style from a styled version 4 text character
00945     SeeAlso:    
00946 
00947 ********************************************************************************************/
00948 
00949 BOOL CDRFilter::GetTextStyleFromChar4(CDRTextStyle *TS, cdrfTextCharStyledV4 *Char, CDRTextStyle *BasedOn)
00950 {
00951     if(BasedOn != 0)
00952         *TS = *BasedOn;
00953     else
00954         *TS = CDRDefaultTextStyle;
00955 
00956     // font name
00957     if((CDRDATA_WORD(Char->Changes) & cdrfSTYLECHANGEV4_FONTNAME) != 0)
00958     {
00959 /*      TCHAR *FontName = GetFontName(Char->FontRef);
00960         if(FontName != 0)
00961         {
00962             TS->FontName = FontName;
00963         }
00964 */
00965         TS->FontReference = CDRDATA_DWORD(Char->FontRef);
00966     }
00967 
00968     // font size
00969     if((CDRDATA_WORD(Char->Changes) & cdrfSTYLECHANGEV4_FONTSIZE) != 0)
00970     {
00971         if(CDRDATA_WORD(Char->FontSize) != 0)
00972         {
00973             TS->FontSize = CDRDATA_WORD(Char->FontSize) * CDRCOORDS_TO_MILLIPOINTS;
00974         }
00975     }
00976 
00977     // update line spacing
00978     TS->LineSpace = (TS->FontSize * (12 * TS->ParaLineSpacePercent)) / 1000;
00979 
00980     // weight
00981     if((CDRDATA_WORD(Char->Changes) & cdrfSTYLECHANGEV4_WEIGHT) != 0)
00982     {
00983         switch(CDRDATA_WORD(Char->FontType))
00984         {
00985             case cdrfFONTTYPEV4_BOLD:
00986                 TS->Bold = TRUE;
00987                 TS->Italic = FALSE;
00988                 break;
00989 
00990             case cdrfFONTTYPEV4_ITALIC:
00991                 TS->Bold = FALSE;
00992                 TS->Italic = TRUE;
00993                 break;
00994 
00995             case cdrfFONTTYPEV4_BOLDITALIC:
00996                 TS->Bold = TRUE;
00997                 TS->Italic = TRUE;
00998                 break;
00999 
01000             default:
01001                 TS->Bold = FALSE;
01002                 TS->Italic = FALSE;
01003                 break;
01004         }
01005     }
01006     
01007     return TRUE;
01008 }
01009 
01010 /********************************************************************************************
01011 
01012 >   BOOL CDRFilter::ConvertText3(cdrfOffsetHeader *Header)
01013 
01014     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01015     Created:    24 03 95
01016     Inputs:     none
01017     Returns:    error flag
01018     Purpose:    converts a version 3 text object to a node. If the object has an unexpected
01019                 format, then FormatError is set and it return *TRUE* - the return value only
01020                 indicated environmental errors such as lack of memory
01021     SeeAlso:    
01022 
01023 ********************************************************************************************/
01024 
01025 BOOL CDRFilter::ConvertText3(cdrfOffsetHeader *Header)
01026 {
01027     // is it a text story?
01028     if(Header->ObjectType == (cdrfOBJTYPE_TEXTSTORY - cdrfOBJTYPE_V3ADD))
01029         IsTextStory = TRUE;
01030 
01031     // get the data from this object
01032     cdrfTextHeaderV3 *Hdr = (cdrfTextHeaderV3 *)FindDataInObject(Header, cdrfOBJOFFSETTYPE_COORDS);
01033 
01034     // it has got some coords, hasn't it?
01035     if(Hdr == 0)
01036     {
01037         FormatError = TRUE;
01038         return TRUE;
01039     }
01040 //TRACEUSER( "Ben", _T("FrameX = %d, FrameY = %d\n"), Hdr->FrameX, Hdr->FrameY);
01041 
01042     INT32 FrameX = CDRDATA_WORD(Hdr->FrameX) * CDRCOORDS_TO_MILLIPOINTS;
01043     INT32 FrameY = CDRDATA_WORD(Hdr->FrameY) * CDRCOORDS_TO_MILLIPOINTS;
01044 
01045     // find pointer to the characters
01046     cdrfTextCharV3 *ThisChar = (cdrfTextCharV3 *)(Hdr + 1);
01047 
01048     // get the base style
01049     CDRTextStyle BaseStyle;
01050 
01051     if(!GetTextStyle3(&BaseStyle, CDRDATA_WORD(Hdr->BaseFontStyle)))
01052         return FALSE;
01053 
01054     // add the justifcation stuff to it
01055     TRACEUSER( "Ben", _T("Justificatoin V3 = %d\n"), Hdr->Justification);
01056     switch(Hdr->Justification)
01057     {
01058         case cdrfJUSTIFICATIONV3_LEFT:
01059         default:
01060             BaseStyle.Just = JLEFT;
01061             break;
01062 
01063         case cdrfJUSTIFICATIONV3_CENTRE:
01064             BaseStyle.Just = JCENTRE;
01065             break;
01066 
01067         case cdrfJUSTIFICATIONV3_RIGHT:
01068             BaseStyle.Just = JRIGHT;
01069             break;
01070     }
01071     
01072     // make a new text story node
01073     TextStory *TSNode = new TextStory;
01074 
01075     if(TSNode == 0)
01076         return FALSE;
01077 
01078     // run through the text...
01079     INT32 NChars = CDRDATA_WORD(Hdr->NCharacters);
01080     INT32 CurrentChar;
01081     INT32 MaximumLineSpace = BaseStyle.LineSpace;
01082     INT32 Lines = 1;
01083     INT32 Depth = 0;
01084 
01085     // make a new text line
01086     TextLine *CurrentLine = new TextLine(TSNode, LASTCHILD);
01087     if(CurrentLine == 0)
01088         goto NoMemory;
01089 
01090     for(CurrentChar = 0; CurrentChar < NChars; CurrentChar++)
01091     {
01092         BOOL HasStyles = FALSE;
01093 
01094         if(ThisChar->Info != 0)
01095             HasStyles = TRUE;
01096 
01097         if(ThisChar->Code >= ' ')
01098         {
01099             TextChar *C = new TextChar(CurrentLine, LASTCHILD, ThisChar->Code);
01100 
01101             if(C == 0)
01102                 goto NoMemory;
01103 
01104             // apply attributes
01105             if(HasStyles)
01106             {
01107                 // it's got styles of it's own, find and apply them
01108                 cdrfTextCharStyledV3 *SC = (cdrfTextCharStyledV3 *)ThisChar;
01109 
01110                 CDRTextStyle ThisStyle;
01111 
01112                 if(!GetTextStyle3(&ThisStyle, CDRDATA_WORD(SC->Style), &BaseStyle))
01113                     return FALSE;
01114 
01115                 if(!ApplyTextAttr(C, &ThisStyle, 0))
01116                     goto NoMemory;
01117         
01118                 if(ThisStyle.LineSpace > MaximumLineSpace)
01119                     MaximumLineSpace = ThisStyle.LineSpace;
01120             }
01121             else
01122             {
01123                 // just apply the normal attributes
01124                 if(!ApplyTextAttr(C, &BaseStyle, 0))
01125                     goto NoMemory;
01126             }
01127         }
01128 
01129         if(ThisChar->Code == cdrfTEXT_NEWLINE)
01130         {
01131             // create a new line...
01132             // apply the line spacing attribute - make a font size attribute
01133 //          TxtLineSpaceAttribute Attr(MaximumLineSpace);
01134             TxtLineSpaceAttribute Attr((FIXED16)(((double)BaseStyle.ParaLineSpacePercent)  / 100));
01135 
01136             // attach
01137             if(!ApplyTextAttrDoApply(CurrentLine, &Attr, FALSE))
01138                 return FALSE;
01139 
01140             // add an EOL
01141             EOLNode *EOL = new EOLNode(CurrentLine, LASTCHILD);
01142             if(EOL == 0)
01143                 goto NoMemory;
01144 
01145             // make a new line
01146             CurrentLine = new TextLine(TSNode, LASTCHILD);
01147             if(CurrentLine == 0)
01148                 goto NoMemory;
01149 
01150             // set things
01151             Lines++;
01152             Depth += MaximumLineSpace;
01153             MaximumLineSpace = BaseStyle.LineSpace;
01154         }
01155 
01156         if(HasStyles)
01157         {
01158 //TRACEUSER( "Ben", _T("Char has styles, code %d (%c)\n"), ThisChar->Code, ThisChar->Code); 
01159             // it's got more than normal bytes in it, so add a few more than usual
01160             ThisChar = (cdrfTextCharV3 *)(((cdrfTextCharStyledV3 *)ThisChar) + 1);
01161         }
01162         else
01163         {
01164 //TRACEUSER( "Ben", _T("Char, code %d (%c)\n"), ThisChar->Code, ThisChar->Code); 
01165             // just a normal character, so simply increment it
01166             ThisChar++;
01167         }
01168     }
01169 
01170     // pop a line space attribute on the last line
01171     {
01172 //      TxtLineSpaceAttribute Attr(MaximumLineSpace);
01173         TxtLineSpaceAttribute Attr((FIXED16)(((double)BaseStyle.ParaLineSpacePercent)  / 100));
01174 
01175         // attach
01176         if(!ApplyTextAttrDoApply(CurrentLine, &Attr, FALSE))
01177             return FALSE;
01178     }
01179 
01180     Depth += MaximumLineSpace;
01181 
01182     // finish the last line with an end of line node
01183     {
01184         EOLNode *EOL = new EOLNode(CurrentLine, LASTCHILD);
01185 
01186         if(EOL == 0)
01187             goto NoMemory;
01188 
01189         // pop a caret at the end of the last line
01190         Node *LastLine = TSNode->FindLastChild();
01191 
01192         if(LastLine == 0)
01193             goto FormError;
01194 
01195         Node *LastLineNode = LastLine->FindLastChild();
01196 
01197         ERROR3IF(LastLineNode == 0, "Line node doesn't have any children");
01198         ERROR3IF(!LastLineNode->IsKindOf(CC_RUNTIME_CLASS(EOLNode)), "Last entry of a line is not an EOL node");
01199         
01200         CaretNode *C = new CaretNode(LastLineNode, PREV);
01201         if(C == 0)
01202             goto NoMemory;
01203     }
01204 
01205     if(IsTextStory)
01206     {
01207         // get a first line height
01208         INT32 FirstLineHeight = (BaseStyle.LineSpace * 10) / 12;
01209 
01210         // work out the rightness shifting
01211         INT32 Right = 0;
01212         if(BaseStyle.Just == JCENTRE)
01213         {
01214             Right = FrameX / 2;
01215         }
01216         else if(BaseStyle.Just == JRIGHT)
01217         {
01218             Right = FrameX;
01219         }
01220 
01221         // set the matrix of the story
01222         TSNode->SetStoryMatrix(Matrix(Right, -FirstLineHeight));
01223 
01224         // bounding box for a text frame
01225         DocRect BBox = DocRect(0, 0 - FrameY, FrameX, 0);
01226 
01227         TextBBoxes.Add(TSNode, &BBox, JLEFT);
01228     
01229         // set it's width to be formatted to
01230         TSNode->SetImportFormatWidth(FrameX);
01231     }
01232     else
01233     {
01234         // set the matrix of the story
01235         TSNode->SetStoryMatrix(Matrix(0,0));
01236 
01237         // bounding box for a artisitic text object - approximate it's width
01238         INT32 Width = (MaximumLineSpace * NChars) / (Lines * 3);
01239 
01240         DocRect BBox = DocRect(0, 0 - Depth, Width, MaximumLineSpace);
01241 
01242         TextBBoxes.Add(TSNode, &BBox, BaseStyle.Just);
01243     
01244         // check it for path on a text
01245         CheckTextForLinks(TSNode, Header);
01246     }
01247 
01248     // set some essential variables
01249     ObjFilled = TRUE;
01250     ObjStroked = FALSE;
01251 
01252     // all done, return...
01253     pMadeNode = TSNode;
01254 
01255     return TRUE;
01256 
01257 NoMemory:
01258     TSNode->Cas