nodetext.cpp

Go to the documentation of this file.
00001 // $Id: nodetext.cpp 1478 2006-07-19 14:44:47Z phil $
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 
00099 // This file contains the implementation of all Text object Nodes
00100 // A TextObject is composed of the following nodes
00101 // TextStory ( The root of the text object subtree )
00102 //      NodeAttributes (Many or none)
00103 //      NodePath 
00104 //      TextLine (Many or one)
00105 //          NodeAttributes (Many or none)
00106 //          TextChar
00107 // See TEXTTLDS.DOC for a description of the structure of the text object data structure
00108 
00109 
00110 #include "camtypes.h"
00111 #include "nodetext.h"
00112 
00113 // Code headers
00114 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00115 //#include "becomea.h"
00116 #include "blobs.h"
00117 #include "cameleps.h"
00118 #include "cliptype.h"
00119 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00120 #include "gdraw.h"
00121 #include "grndrgn.h"
00122 #include "lineattr.h"
00123 #include "nodetxtl.h"
00124 #include "nodetxts.h"
00125 #include "snap.h"
00126 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00127 #include "texttool.h"
00128 #include "textops.h"
00129 #include "attrmap.h"
00130 #include "printctl.h"
00131 #include "cxftext.h"
00132 #include "nodepath.h"
00133 #include "swfrndr.h"
00134 
00135 // Resource headers
00136 //#include "mario.h"
00137 //#include "peter.h"
00138 //#include "simon.h"
00139 
00140 #include "webattr.h"            //For the GetClickableRectangle functions
00141 #include "brshattr.h"
00142 
00143 #include "ai_epsrr.h"
00144 
00145 DECLARE_SOURCE("$Revision: 1478 $")
00146 
00147 CC_IMPLEMENT_DYNAMIC(VisibleTextNode, BaseTextClass)
00148 CC_IMPLEMENT_DYNAMIC(CaretNode, VisibleTextNode)
00149 CC_IMPLEMENT_DYNAMIC(AbstractTextChar, VisibleTextNode)
00150 CC_IMPLEMENT_DYNAMIC(EOLNode,  AbstractTextChar)
00151 CC_IMPLEMENT_DYNAMIC(TextChar, AbstractTextChar)
00152 CC_IMPLEMENT_DYNAMIC(KernCode, AbstractTextChar)
00153 CC_IMPLEMENT_DYNAMIC(HorizontalTab, AbstractTextChar)
00154 
00155 // Declare smart memory handling in Debug builds
00156 #define new CAM_DEBUG_NEW
00157 
00158 
00159 /********************************************************************************************
00160 >   VisibleTextNode::VisibleTextNode()
00161 
00162     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00163     Created:    21/12/94
00164     Purpose:    Simple VisibleTextNode constructor, it is required so that SimpleCopy will work.
00165 ********************************************************************************************/
00166 
00167 VisibleTextNode::VisibleTextNode(): BaseTextClass() // Call the base class
00168 {
00169     Init();
00170 }
00171 
00172  
00173 /********************************************************************************************
00174 >   VisibleTextNode::VisibleTextNode(Node* ContextNode, AttachNodeDirection Direction)
00175 
00176     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00177     Created:    07/02/95
00178     Inputs:     ContextNode: Pointer to a node which this node is to be attached to.     
00179         
00180                 Direction: 
00181             
00182                 Specifies the direction in which the node is to be attached to the 
00183                 ContextNode. The values this variable can take are as follows: 
00184                                   
00185                 PREV      : Attach node as a previous sibling of the context node
00186                 NEXT      : Attach node as a next sibling of the context node
00187                 FIRSTCHILD: Attach node as the first child of the context node
00188                 LASTCHILD : Attach node as a last child of the context node  
00189                 
00190     Purpose:    The main VisibleTextNode constructor
00191 ********************************************************************************************/
00192 
00193 VisibleTextNode::VisibleTextNode(Node* ContextNode,  
00194                                  AttachNodeDirection Direction): BaseTextClass(ContextNode, Direction)
00195 {
00196     Init();
00197 }
00198 
00199 
00200 /********************************************************************************************
00201 >   void VisibleTextNode::Init()
00202 
00203     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00204     Created:    14/3/95
00205     Purpose:    Initialise the members of a VisibleTextNode.  Called by all constructors.
00206 ********************************************************************************************/
00207 
00208 void VisibleTextNode::Init()
00209 {
00210     CharMatrix          = Matrix(0,0);
00211     PosInLine           = 0;
00212     IsBoundingRectValid = FALSE;
00213 }
00214 
00215 
00216 /********************************************************************************************
00217 >   VisibleTextNode* VisibleTextNode::FindNextVTNInStory()
00218 
00219     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00220     Created:    14/2/95
00221     Returns:    A pointer to the next VisibleTextNode in the TextStory
00222     Purpose:    Finds the next VisibleTextNode in the TextStory. The routine searches
00223                 across TextLines.   
00224     Errors:     An ERROR3 will be caused if the node is not on a line which is the child
00225                 of a TextStory.
00226 ********************************************************************************************/
00227 
00228 VisibleTextNode* VisibleTextNode::FindNextVTNInStory()
00229 {
00230     Node* Line = FindParent(); 
00231 
00232     // Be cautious
00233     ERROR3IF(Line == NULL, "VisibleTextNode has no parent"); 
00234     ERROR3IF(!(IS_A(Line, TextLine)), "Parent of VisibleTextNode is not a TextLine"); 
00235 
00236     Node* Story = Line->FindParent(); 
00237 
00238     ERROR3IF(Story == NULL, "TextLine has no parent"); 
00239     ERROR3IF(!(IS_A(Story, TextStory)), "Parent of TextLine is not a TextStory"); 
00240 
00241     Node* n = this; 
00242 
00243     // Loop until we have found a next VisibleTextNode
00244     // This code is an optimised depth first routine
00245     do
00246     {
00247         if (n->FindNext())  // Has the current node got a next sibling
00248         {
00249             n = n->FindNext();  // Let's visit it 
00250 
00251             if (IS_A(n,TextLine))
00252             {
00253                 // We have skipped to the next line, let's go to its first child if
00254                 // it has one
00255                 if (n->FindFirstChild())
00256                 {
00257                     n = n->FindFirstChild(); 
00258                 }
00259             }
00260 
00261             if (n->IsAVisibleTextNode())
00262             {
00263                 // Found one !
00264                 return (VisibleTextNode*)n; 
00265             }
00266 
00267         }
00268         else
00269         {
00270             // The only way is up 
00271             n = n->FindParent(); 
00272         }   
00273         ERROR3IF(n == NULL, "We haven't found the parent TextStory"); 
00274     }
00275     while (n != Story);
00276 
00277     return NULL; // No more  
00278 } 
00279 
00280 
00281 /********************************************************************************************
00282 >   VisibleTextNode* VisibleTextNode::FindPrevVTNInStory()
00283 
00284     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00285     Created:    14/2/95
00286     Returns:    A pointer to the previous VisibleTextNode in the TextStory
00287     Purpose:    Finds the previous VisibleTextNode in the TextStory. The routine searches
00288                 across TextLines.   
00289     Errors:     An ERROR3 will be caused if the node is not on a line which is the child
00290                 of a TextStory.
00291 ********************************************************************************************/
00292 
00293 VisibleTextNode* VisibleTextNode::FindPrevVTNInStory()
00294 {
00295     Node* Line = FindParent(); 
00296 
00297     // Be cautious
00298     ERROR3IF(Line == NULL, "VisibleTextNode has no parent"); 
00299     ERROR3IF(!(IS_A(Line, TextLine)), "Parent of VisibleTextNode is not a TextLine"); 
00300 
00301     Node* Story = Line->FindParent(); 
00302 
00303     ERROR3IF(Story == NULL, "TextLine has no parent"); 
00304     ERROR3IF(!(IS_A(Story, TextStory)), "Parent of TextLine is not a TextStory"); 
00305 
00306     Node* n = this; 
00307 
00308     // Loop until we have found a previous VisibleTextNode
00309     // This code is an optimised prev depth first routine
00310     do
00311     {
00312         if (n->FindPrevious())      // Has the current node got a previous sibling
00313         {
00314             n = n->FindPrevious();  // Let's visit it 
00315 
00316             if (IS_A(n, TextLine))
00317             {
00318                 // Next node to check is the last child of this TextLine
00319                 Node* LastChild = n->FindLastChild(); 
00320                 if (LastChild != NULL)
00321                 {
00322                     n = LastChild;
00323                 } 
00324             }                                 
00325 
00326             if (n->IsAVisibleTextNode())
00327             {
00328                 // Found one !
00329                 return (VisibleTextNode*)n; 
00330             }
00331 
00332         }
00333         else
00334         {
00335             // The only way is up 
00336             n = n->FindParent(); 
00337         }   
00338         ERROR3IF(n == NULL, "We haven't found the parent TextStory"); 
00339     }
00340     while (n != Story);
00341 
00342     return NULL; // No more  
00343 } 
00344 
00345 
00346 /********************************************************************************************
00347 >   AbstractTextChar* VisibleTextNode::FindNextAbstractTextCharInStory()
00348 
00349     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00350     Created:    22/3/95
00351     Returns:    A pointer to the next AbstractTextChar in the TextStory
00352 ********************************************************************************************/
00353 
00354 AbstractTextChar* VisibleTextNode::FindNextAbstractTextCharInStory()
00355 {
00356     VisibleTextNode* pChar = FindNextVTNInStory();
00357     while (pChar!=NULL && !pChar->IsAnAbstractTextChar())
00358         pChar = pChar->FindNextVTNInStory();
00359 
00360     return (AbstractTextChar*)pChar;
00361 } 
00362 
00363 
00364 /********************************************************************************************
00365 >   AbstractTextChar* VisibleTextNode::FindPrevAbstractTextCharInStory()
00366 
00367     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00368     Created:    22/3/95
00369     Returns:    A pointer to the previous AbstractTextChar in the TextStory
00370 ********************************************************************************************/
00371 
00372 AbstractTextChar* VisibleTextNode::FindPrevAbstractTextCharInStory()
00373 {
00374     VisibleTextNode* pChar = FindPrevVTNInStory();
00375     while (pChar!=NULL && !pChar->IsAnAbstractTextChar())
00376         pChar = pChar->FindPrevVTNInStory();
00377 
00378     return (AbstractTextChar*)pChar;
00379 } 
00380 
00381 
00382 /********************************************************************************************
00383 >   TextChar* VisibleTextNode::FindNextTextCharInStory()
00384 
00385     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00386     Created:    22/3/95
00387     Returns:    A pointer to the next TextChar in the TextStory
00388 ********************************************************************************************/
00389 
00390 TextChar* VisibleTextNode::FindNextTextCharInStory()
00391 {
00392     VisibleTextNode* pChar = FindNextVTNInStory();
00393     while (pChar!=NULL && !IS_A(pChar,TextChar))
00394         pChar = pChar->FindNextVTNInStory();
00395 
00396     return (TextChar*)pChar;
00397 } 
00398 
00399 
00400 /********************************************************************************************
00401 >   TextChar* VisibleTextNode::FindPrevTextCharInStory()
00402 
00403     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00404     Created:    22/3/95
00405     Returns:    A pointer to the previous TextChar in the TextStory
00406 ********************************************************************************************/
00407 
00408 TextChar* VisibleTextNode::FindPrevTextCharInStory()
00409 {
00410     VisibleTextNode* pChar = FindPrevVTNInStory();
00411     while (pChar!=NULL && !IS_A(pChar,TextChar))
00412         pChar = pChar->FindPrevVTNInStory();
00413 
00414     return (TextChar*)pChar;
00415 } 
00416 
00417 
00418 /********************************************************************************************
00419 >   VisibleTextNode* VisibleTextNode::FindNextVTNInLine()
00420 
00421     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00422     Created:    8/1/96
00423     Returns:    A pointer to the next VTN in the line
00424 ********************************************************************************************/
00425 
00426 VisibleTextNode* VisibleTextNode::FindNextVTNInLine()
00427 {
00428     Node* pNode = FindNext();
00429     while (pNode!=NULL && pNode->IsAVisibleTextNode()==FALSE)
00430         pNode = pNode->FindNext();
00431 
00432     return (VisibleTextNode*)pNode;
00433 } 
00434 
00435 /********************************************************************************************
00436 >   AbstractTextChar* VisibleTextNode::FindNextAbstractTextCharInLine()
00437 
00438     Author:     Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com>
00439     Created:    27/3/97
00440     Returns:    A pointer to the next AbstractTextChar in the line
00441 ********************************************************************************************/
00442 
00443 AbstractTextChar* VisibleTextNode::FindNextAbstractTextCharInLine()
00444 {
00445     Node* pNode = FindNext();
00446     while (pNode!=NULL && pNode->IsAnAbstractTextChar()==FALSE)
00447         pNode = pNode->FindNext();
00448 
00449     return (AbstractTextChar*)pNode;
00450 } 
00451 
00452 
00453 
00454 /********************************************************************************************
00455 >   VisibleTextNode* VisibleTextNode::FindPrevVTNInLine()
00456 
00457     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00458     Created:    8/1/96
00459     Returns:    A pointer to the previous VTN in the line
00460 ********************************************************************************************/
00461 
00462 VisibleTextNode* VisibleTextNode::FindPrevVTNInLine()
00463 {
00464     Node* pNode = FindPrevious();
00465     while (pNode!=NULL && pNode->IsAVisibleTextNode()==FALSE)
00466         pNode = pNode->FindPrevious();
00467 
00468     return (VisibleTextNode*)pNode;
00469 } 
00470 
00471 /********************************************************************************************
00472 >   AbstractTextChar* VisibleTextNode::FindPrevAbstractTextCharInLine()
00473 
00474     Author:     Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com>
00475     Created:    27/3/97
00476     Returns:    A pointer to the prev AbstractTextChar in the line
00477 ********************************************************************************************/
00478 
00479 AbstractTextChar* VisibleTextNode::FindPrevAbstractTextCharInLine()
00480 {
00481     Node* pNode = FindPrevious();
00482     while (pNode!=NULL && pNode->IsAnAbstractTextChar()==FALSE)
00483         pNode = pNode->FindPrevious();
00484 
00485     return (AbstractTextChar*)pNode;
00486 } 
00487 
00488 /********************************************************************************************
00489 >   TextLine* VisibleTextNode::FindParentLine()
00490 
00491     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00492     Created:    24/7/96
00493     Returns:    A pointer to the parent TextLine
00494 ********************************************************************************************/
00495 
00496 TextLine* VisibleTextNode::FindParentLine()
00497 {
00498     return (TextLine*)(this->FindParent(CC_RUNTIME_CLASS(TextLine)));
00499 } 
00500 
00501 
00502 /********************************************************************************************
00503 >   virtual CopyType VisibleTextNode::GetCopyType()
00504 
00505     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00506     Created:    3/5/95
00507     Returns:    A copy type describing how to copy this object
00508     Purpose:    This function returns a type describing how this object is to be copied.
00509                 The fuction is called from the low level copy operation CopyObjects.
00510                 There are two options at present, these being SIMPLECOPY and COMPLEXCOPY.
00511                 SIMPLECOPY indicates that the node can be copied by a call to its virtual
00512                 function SimpleCopy(). 
00513                 COMPLEXCOPY however indicates that the node needs to do its own thing when
00514                 copying and must be called via the ComplexCopy() virtual function. This
00515                 virtual will likely return a tree of copied objects rather than just a
00516                 copy of itself.
00517 ********************************************************************************************/
00518 
00519 CopyType VisibleTextNode::GetCopyType()
00520 {
00521     return COMPLEXCOPY;
00522 }
00523 
00524 
00525 /********************************************************************************************
00526 >   Node* VisibleTextNode::SimpleCopy()
00527 
00528     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00529     Created:    21/12/94
00530     Returns:    NULL (See below)
00531     Purpose:    It is illegal to copy a VisibleTextNode (it's abstract), therefore this 
00532                 function will generate an error if called.         
00533 ********************************************************************************************/
00534 
00535 Node* VisibleTextNode::SimpleCopy()
00536 {
00537     ERROR2(NULL, "Trying to copy abstract VisibleTextNode !"); 
00538 }
00539 
00540 
00541 /********************************************************************************************
00542 >   virtual INT32 VisibleTextNode::ComplexCopy(CopyStage Stage, Range& RangeToCopy, Node** pOutput)
00543 
00544     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00545     Created:    3/5/95
00546     Inputs:     Stage       - either COPYOBJECT
00547                                      COPYFINISHED
00548                 RangeToCopy - Describes the range which is currently being copied.
00549                 pOutput     - Depends on the Stage parameter
00550                               if Stage=
00551                               COPYOBJECT
00552                                 Then the node pointer pOutput points at NULL. It should be
00553                                 set on exit to point at the copied object or tree of objects
00554                               COPYFINISHED
00555                                 Then the node pointer pOutput points at the resulting copy
00556                                 from COPYOBJECT inserted into the destination tree.
00557     Outputs:    pOutput
00558 
00559     Returns:    -1  = The routine failed to make a copy.
00560                  0  = No copy has been made.
00561                 +1  = pOutput points to the copy.
00562 
00563     Purpose:    Create a complex copy of this node. This node has overridden GetCopyType()
00564                 to return COMPLEXCOPY which means, when copying to the clipboard it must
00565                 make a copy of itself and whatever else it needs. The resulting tree will
00566                 be attached as the last child of the clipboard root.
00567                 The routine will be called twice during a copy. Once when Stage==COPYOBJECT
00568                 and once when Stage==COPYFINISHED. It is only necessary to return a copy
00569                 during COPYOBJECT. COPYFINISHED can be used to tidy up and flags the node
00570                 may set during COPYOBJECT.
00571 
00572                 Note:
00573                 Nodes may well require the use of flags to create a sensible complex copy.
00574                 Every selected node will be called to copy itself during a CopyToClipboard
00575                 whether they are SIMPLECOPY or COMPLEXCOPY types. Hence if the first call
00576                 to a node creates a complete tree of objects including nodes which will
00577                 likely be called by the clipboard copy routine further into its range ie
00578                 they are selected as well, the node should keep a flag indicating it has
00579                 already copied them and return 0 from the routine on subsequent calls.
00580                 A concrete example of this is the text object. Any number of characters
00581                 can be selected and copied to the clipboard. A character class specifies
00582                 it is a COMPLEXCOPY node. Each selected character will then get called
00583                 to make a complex copy of itself. To make a copy the character will ask
00584                 the parent text story to make a copy of all selected nodes, including
00585                 itself and lines. It needs to flag itself at this point as further chars
00586                 in the text story will be asked to do the same. This will prevent multiple
00587                 text stories from being created, one for every selected character.
00588 ********************************************************************************************/
00589 
00590 INT32 VisibleTextNode::ComplexCopy(CopyStage Stage, Range& RangeToCopy, Node** pOutput)
00591 {
00592     TextStory* pTextStory = FindParentStory();
00593     ERROR2IF(pTextStory==NULL,FALSE,"VisibleTextNode::ComplexCopy() - pTextStory==NULL");
00594     return pTextStory->BaseComplexCopy(Stage, RangeToCopy, pOutput);
00595 }
00596 
00597 
00598 /***********************************************************************************************
00599 >   void VisibleTextNode::CopyNodeContents(VisibleTextNode* NodeCopy)
00600 
00601     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00602     Created:    28/4/93
00603     Outputs:    A copy of this node
00604     Purpose:    This method copies the node's contents to the node pointed to by NodeCopy.
00605     Errors:     An ERROR3 will occur if NodeCopy is NULL
00606 ***********************************************************************************************/
00607 
00608 void VisibleTextNode::CopyNodeContents(VisibleTextNode* NodeCopy)
00609 {
00610     // Ask the base class to do its bit
00611     Node::CopyNodeContents(NodeCopy);
00612 
00613     // copy specifics
00614     NodeCopy->CharMatrix = CharMatrix;
00615     NodeCopy->PosInLine  = PosInLine;
00616 }
00617 
00618 
00619 /********************************************************************************************
00620 >   virtual INT32 VisibleTextNode::ComplexHide(UndoableOperation* pOp, Node* pNextNode)
00621 
00622     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00623     Created:    3/5/95
00624     Inputs:     pOp         - a pointer to an undoable operation
00625                 pNextNode   - a pointer to the next node in range.
00626     Returns:    -1  = The routine failed to hide this node.
00627                  0  = Ignored, this object does not support complex hide operations, so
00628                       carry on and hide the node as normal.
00629                 +1  = The node and possibly various others have been hidden correctly.
00630     Purpose:    Override the node level virtual function ComplexHide. This gives us a chance to
00631                 get in and hide the various selected members of a text story sensibly. We
00632                 hide all necessary nodes when the last member of the text story is called to
00633                 complex hide itself, otherwise we may corrupt the range being scanned
00634 ********************************************************************************************/
00635 
00636 INT32 VisibleTextNode::ComplexHide(UndoableOperation* pOp, Node* pNextNode)
00637 {
00638     // if there is no next node in the range then we need to hide all nodes
00639     BOOL CallComplexHide = TRUE;
00640     TextStory* pThisStory = this->FindParentStory();
00641     ERROR2IF(pThisStory==NULL,FALSE,"VisibleTextNode::ComplexHide() - pThisStory==NULL");
00642 
00643     if (pNextNode)
00644     {
00645         if ( pNextNode->IsAVisibleTextNode() || IS_A(pNextNode,TextLine) )
00646         {
00647             TextStory* pTextStory = (TextStory*)(pNextNode->FindParent(CC_RUNTIME_CLASS(TextStory)));
00648             ERROR2IF(pTextStory==NULL,FALSE,"VisibleTextNode::ComplexHide() - pTextStory==NULL");
00649             if (pThisStory==pTextStory)
00650                 CallComplexHide=FALSE;
00651         }
00652     }
00653 
00654     if (CallComplexHide)
00655         return pThisStory->BaseComplexHide(pOp);
00656     else
00657         return 1;
00658 }
00659 
00660 
00661 /********************************************************************************************
00662 >   UINT32 VisibleTextNode::GetNodeSize() const 
00663 
00664     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00665     Created:    21/12/94
00666     Returns:    The size of the node in bytes
00667     Purpose:    For finding the size of the VisibleTextNode. 
00668 ********************************************************************************************/
00669 
00670 UINT32 VisibleTextNode::GetNodeSize() const 
00671 {
00672     ERROR3("Tring to find the size of abstract VisibleTextNode"); 
00673     return (sizeof(VisibleTextNode)); 
00674 }
00675 
00676 
00677 /********************************************************************************************
00678 >   void VisibleTextNode::GetDebugDetails(StringBase* Str) 
00679 
00680     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00681     Created:    1/2/95
00682     Outputs:    Str: String giving debug info about the node
00683     Purpose:    For obtaining debug information about the Node. 
00684                 This fn can be deleted before we ship 
00685 ********************************************************************************************/
00686 
00687 void VisibleTextNode::GetDebugDetails(StringBase* Str)
00688 {
00689 #if DEBUG_TREE
00690     BaseTextClass::GetDebugDetails(Str);
00691 
00692     String_256 TempStr;
00693     String_256 TempStr2;
00694     TCHAR       floatStr[20];
00695 
00696     // dump the character matrix
00697     fixed16 abcd[4];
00698     INT32   ef[2];
00699     CharMatrix.GetComponents(abcd, ef);
00700 
00701     TempStr._MakeMsg( TEXT("\r\nMatrix\r\n"));   
00702     (*Str) += TempStr;
00703     camSnprintf( floatStr, 20, _T("%f,%f"), abcd[0].MakeDouble(), abcd[1].MakeDouble());
00704     TempStr._MakeMsg( TEXT("a, b :\t#1%s\r\n"), floatStr);
00705     (*Str) += TempStr;
00706     camSnprintf( floatStr, 20, _T("%f,%f"), abcd[2].MakeDouble(), abcd[3].MakeDouble());
00707     TempStr._MakeMsg( TEXT("c, d :\t#1%s\r\n"), floatStr);
00708     (*Str) += TempStr;
00709     TempStr._MakeMsg( TEXT("e, f :\t#1%ld,\t#2%ld\r\n"), ef[0], ef[1]);
00710     (*Str) += TempStr;
00711 #endif
00712 }
00713 
00714 
00715 /********************************************************************************************
00716 >   BOOL VisibleTextNode::GetStoryAndCharMatrix(Matrix* pMatrix)
00717 
00718     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00719     Created:    19/3/95
00720     Outputs:    pMatrix - output matrix
00721     Reutrns:    FALSE if fails
00722     Purpose:    set the given matrix to be the concatenation of the TextStory and VTN matrices
00723 ********************************************************************************************/
00724 
00725 BOOL VisibleTextNode::GetStoryAndCharMatrix(Matrix* pMatrix)
00726 {
00727     ERROR2IF(pMatrix==NULL,FALSE,"VisibleTextNode::GetStoryAndCharMatrix() - pMatrix==NULL");
00728 
00729     // get the VTN matrix, then concatenate the TextStory matrix
00730     *pMatrix=CharMatrix;
00731     TextStory* pTextStory = this->FindParentStory();
00732     ERROR2IF(pTextStory==NULL,FALSE,"VisibleTextNode::GetStoryAndCharMatrix() - pTextStory==NULL");
00733     *pMatrix*=*(pTextStory->GetpStoryMatrix());
00734 
00735     return TRUE;
00736  }
00737 
00738 
00739 /********************************************************************************************
00740 >   BOOL VisibleTextNode::RenderChildAttrs(RenderRegion* pRenderRegion)
00741 
00742     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00743     Created:    4/4/95
00744     Inputs:     pRenderRegion - 
00745     Returns:    FALSE if fails
00746     Purpose:    Render any first level children attributes into the region
00747 ********************************************************************************************/
00748 
00749 BOOL VisibleTextNode::RenderChildAttrs(RenderRegion* pRenderRegion)
00750 {
00751     ERROR2IF(pRenderRegion==NULL,FALSE,"VisibleTextNode::RenderChildAttrs() - pRenderRegion==NULL");
00752 
00753     Node* pChildNode=FindFirstChild();
00754     while (pChildNode)
00755     {
00756         if (pChildNode->IsAnAttribute())
00757             pChildNode->Render(pRenderRegion);
00758         pChildNode=pChildNode->FindNext();
00759     }
00760 
00761     return TRUE;
00762 }
00763 
00764 
00765 /********************************************************************************************
00766 >   MILLIPOINT VisibleTextNode::CalcCharDistAlongLine(BOOL IncludeThisChar)
00767 
00768     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00769     Created:    12/5/95
00770     Inputs:     IncludeThisChar - TRUE to include this character in the distance,
00771                                   FALSE to leave it out
00772     Returns:    The distance along the TextLine that this character is at
00773     Purpose:    Finds the distance along the text line of this character.
00774                 You can optionally include the width of this character in the sum.
00775 ********************************************************************************************/
00776 
00777 MILLIPOINT VisibleTextNode::CalcCharDistAlongLine(BOOL IncludeThisChar)
00778 {
00779     if (IncludeThisChar)
00780         return GetPosInLine()+GetCharAdvance();
00781     else
00782         return GetPosInLine();
00783 }
00784 
00785 
00786 /********************************************************************************************
00787 >   BOOL VisibleTextNode::WrapRestOfLineForward(UndoableOperation* pUndoOp)
00788 
00789     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00790     Created:    8/7/96
00791     Inputs:     pUndoOp   - pointer to undoable op
00792     Returns:    FALSE if fails
00793     Purpose:    Wrap all nodes from this VTN (inc) to last VTN forward to start of next line
00794                 If the line containing this VTN is hard (ends in an EOL)
00795                 create a new line to wrap the text onto
00796 ********************************************************************************************/
00797 
00798 BOOL VisibleTextNode::WrapRestOfLineForward(UndoableOperation* pUndoOp)
00799 {
00800     // get info about the source line
00801     TextLine* pSrcLine = this->FindParentLine();
00802     ERROR2IF(pSrcLine==NULL,FALSE,"VisibleTextNode::WrapRestOfLineForward() - pSrcLine==NULL");
00803     VisibleTextNode* pLastVTNToMove = pSrcLine->FindLastVTN();
00804     ERROR2IF(pLastVTNToMove==NULL,FALSE,"VisibleTextNode::WrapRestOfLineForward() - no VTN's on soft line");
00805 
00806     // if SrcLine soft, find next line (localising non-LLA attrs on it) else create a new line
00807     AttrTypeSet* pAttrSet = NULL;   // assume creating new line so all attrs need localising
00808     TextLine*    pDstLine = NULL;
00809     BOOL         ok       = TRUE;
00810     if (pLastVTNToMove->IsAnEOLNode())
00811     {
00812         pDstLine = new TextLine;
00813         if (pDstLine==NULL)
00814             return FALSE;
00815         pSrcLine->CopyNodeContents(pDstLine);   // copy cached line level attr info
00816         if (ok) ok = pDstLine->DoInsertNewNode(pUndoOp,pSrcLine,NEXT);
00817     }
00818     else
00819     {
00820         pDstLine = pSrcLine->FindNextLine();
00821         ERROR2IF(pDstLine==NULL,FALSE,"VisibleTextNode::WrapRestOfLineForward() - no next line after soft line");
00822 
00823         pAttrSet = new AttrTypeSet();
00824         if (ok) ok = pSrcLine->AddNonLineLevelDescendantAttrsToSet(pAttrSet);
00825         if (ok) ok = pDstLine->AddNonLineLevelDescendantAttrsToSet(pAttrSet);
00826 
00827         if (ok) ok = pDstLine->DoLocaliseCommonAttributes(pUndoOp,FALSE,FALSE,pAttrSet);
00828     }
00829 
00830     // get context node and attach direction for attaching text as first objects in dest line
00831     Node* pAttachNode = pDstLine;
00832     AttachNodeDirection AttachDir = FIRSTCHILD;
00833     pDstLine->GetAttachNodeAndDirectionToAttachFirstChildObject(&pAttachNode,&AttachDir);
00834 
00835     // localise on SrcLine, move text to DstLine, then factor out on both
00836     // Localise/FactorOut not global as attrs on story should never change
00837     if (ok) ok = pSrcLine->DoLocaliseCommonAttributes(pUndoOp,FALSE,FALSE,pAttrSet);
00838     if (ok) ok = this->DoMoveNodes(pUndoOp, pLastVTNToMove, pAttachNode, AttachDir);
00839     if (ok) ok = pSrcLine->DoFactorOutCommonChildAttributes(pUndoOp,FALSE,pAttrSet);
00840     if (ok) ok = pDstLine->DoFactorOutCommonChildAttributes(pUndoOp,FALSE,pAttrSet);
00841 
00842     if (pAttrSet!=NULL)
00843     {
00844         pAttrSet->DeleteAll();
00845         delete pAttrSet;
00846     }
00847 
00848     return ok;
00849 }
00850 
00851 
00852 /********************************************************************************************
00853 >   BOOL VisibleTextNode::WrapFromStartOfLineBack(UndoableOperation* pUndoOp)
00854 
00855     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00856     Created:    8/7/96
00857     Inputs:     pUndoOp - pointer to undoable operation
00858     Returns:    FALSE if fails
00859     Purpose:    Wrap all chars upto this VTN (inc) back to the end of the previous line
00860                 If this line is then empty, hide it
00861 ********************************************************************************************/
00862 
00863 BOOL VisibleTextNode::WrapFromStartOfLineBack(UndoableOperation* pUndoOp)
00864 {
00865     // get info about this and previous line
00866     TextLine* pThisLine = this->FindParentLine();
00867     ERROR2IF(pThisLine==NULL,FALSE,"VisibleTextNode::WrapFromStartOfLineBack() - pThisLine==NULL");
00868     VisibleTextNode* pFirstVTN = pThisLine->FindFirstVTN();
00869     ERROR2IF(pFirstVTN==NULL,FALSE,"VisibleTextNode::WrapFromStartOfLineBack() - no VTN on this line!");
00870     TextLine* pPrevLine = pThisLine->FindPrevLine();
00871     ERROR2IF(pPrevLine==NULL,FALSE,"VisibleTextNode::WrapFromStartOfLineBack() - pPrevLine==NULL");
00872     ERROR2IF(pPrevLine->FindEOLNode()!=NULL,FALSE,"VisibleTextNode::WrapFromStartOfLineBack() - trying to wrap back onto a hard line!");
00873 
00874     // get a set of non line level attrs, which are to be localised to char level
00875     AttrTypeSet NonLineLevelAttrs;
00876     BOOL    ok = pThisLine->AddNonLineLevelDescendantAttrsToSet(&NonLineLevelAttrs);
00877     if (ok) ok = pPrevLine->AddNonLineLevelDescendantAttrsToSet(&NonLineLevelAttrs);
00878 
00879     // move ALL the nodes from first VTN on line to this VTN back to end of prev line
00880     // if wrapping whole line back, hide the empty line
00881     // since previous line is soft assumes this and prev lines have same line level attrs
00882     // Localise/FactorOut global as Line Level attrs on story may change change
00883     BOOL WholeLine = (this->FindNextVTNInLine()==NULL);
00884     if (ok) ok = pThisLine->DoLocaliseCommonAttributes(pUndoOp,FALSE,TRUE,&NonLineLevelAttrs);
00885     if (ok) ok = pPrevLine->DoLocaliseCommonAttributes(pUndoOp,FALSE,TRUE,&NonLineLevelAttrs);
00886     if (ok) ok = pFirstVTN->DoMoveNodes(pUndoOp, this, pPrevLine, LASTCHILD);
00887     if (ok &&  WholeLine) ok = pThisLine->DoHideNode(pUndoOp);
00888     if (ok && !WholeLine) ok = pThisLine->DoFactorOutCommonChildAttributes(pUndoOp,TRUE,&NonLineLevelAttrs);
00889     if (ok) ok = pPrevLine->DoFactorOutCommonChildAttributes(pUndoOp,TRUE,&NonLineLevelAttrs);
00890 
00891     return ok;
00892 }
00893 
00894 
00895 /********************************************************************************************
00896 >   BOOL VisibleTextNode::DoMoveNodes(UndoableOperation*  pUndoOp,
00897                                       VisibleTextNode*    pLastVTN,
00898                                       Node*               pDestNode,
00899                                       AttachNodeDirection Direction)
00900 
00901     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00902     Created:    7/2/96
00903     Inputs:     pUndoOp   - pointer to undoable operation (NULL if not undoable)
00904                 pLastVTN  - pointer to VTN after last node to move (must be on the same line as this)
00905                 pDestNode - pointer to node to attach to
00906                 Direction - direction to attach in
00907     Returns:    FALSE if fails
00908     Purpose:    Move ALL nodes from this VTN to LastVTN to pDestNode in the specified direction
00909     Assumes:    First and last VTNs are on the same line
00910     Note:       only VTN in range are moved so hidden nodes don't cause undo bloat!
00911 ********************************************************************************************/
00912 
00913 BOOL VisibleTextNode::DoMoveNodes(UndoableOperation*  pUndoOp,
00914                                   VisibleTextNode*    pLastVTN,
00915                                   Node*               pDestNode,
00916                                   AttachNodeDirection Direction)
00917 {
00918     ERROR2IF( pLastVTN==NULL,FALSE,"VisibleTextNode::DoMoveNodes() - pLastVTN==NULL");
00919     ERROR2IF(pDestNode==NULL,FALSE,"VisibleTextNode::DoMoveNodes() - pDestNode==NULL");
00920 
00921     // move all VTN in the range to the specified location
00922     // however, can only move the caret once there are are some cahrs on the new line
00923     Node*            pPrevDestNode = pDestNode;
00924     VisibleTextNode* pSrcVTN       = this;
00925     while (pPrevDestNode!=pLastVTN)
00926     {
00927         ERROR2IF(pSrcVTN==NULL,FALSE,"VisibleTextNode::DoMoveNodes() - did not find pLastVTN");
00928         VisibleTextNode* pNextSrcVTN = pSrcVTN->FindNextVTNInLine();
00929         if (pSrcVTN->DoMoveNode(pUndoOp, pPrevDestNode, Direction)==FALSE)
00930             return FALSE;
00931         Direction     = NEXT;       // all subsequent VTN moved after previous
00932         pPrevDestNode = pSrcVTN;
00933         pSrcVTN = pNextSrcVTN;
00934     }
00935 
00936     return TRUE;
00937 }
00938 
00939 
00940 /********************************************************************************************
00941 >   BOOL VisibleTextNode::DoMoveNode(UndoableOperation*  pUndoOp,
00942                                      Node*               pDestNode,
00943                                      AttachNodeDirection Direction)
00944 
00945     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00946     Created:    7/2/96
00947     Inputs:     pUndoOp   - pointer to undoable operation (NULL if not undoable)
00948                 pDestNode - pointer to node to attach to
00949                 Direction - direction to attach in
00950     Returns:    FALSE if fails
00951     Purpose:    Move this VTN to the specified location, flagging it 'Affected' in
00952                 the old and new position
00953 ********************************************************************************************/
00954 
00955 BOOL VisibleTextNode::DoMoveNode(UndoableOperation*  pUndoOp,
00956                                  Node*               pDestNode,
00957                                  AttachNodeDirection Direction)
00958 {
00959     ERROR2IF(pDestNode==NULL,FALSE,"VisibleTextNode::DoMoveNode() - pDestNode==NULL");
00960     TextStory* pTextStory = this->FindParentStory();
00961     ERROR2IF(pTextStory==NULL,FALSE,"VisibleTextNode::DoMoveNode() - caret has no parent story!");
00962 
00963     // flag node affected in old position (and parents)
00964     FlagNodeAndDescendantsAffectedAndParentsHaveDescendantAffected();
00965     
00966     // if selected, deselect to maintain 'parent of selected' flag
00967     BOOL selected = IsSelected();
00968     if (selected)
00969         SetSelected(FALSE);
00970 
00971     // if the caret (remember its position if undoable) always move it non-undoably
00972     // else just move the char, non-undoably if required
00973     // Note:must remember caret's old pos as if it is moved onto a new line,
00974     //      when it is undone, the caret will be a child of the hidden line
00975     //      and PrePostTextAction cannot cope with restoring the caret once hidden
00976     if (this->IsACaret())
00977     {
00978 #if !defined(EXCLUDE_FROM_RALPH)
00979         if (pUndoOp!=NULL)
00980             if (!PositionCaretAction::DoStoreCaretPosition(pUndoOp,pTextStory))
00981                 return FALSE;
00982 #endif
00983         MoveNode(pDestNode,Direction);
00984     }
00985     else
00986     {
00987         if (pUndoOp==NULL)
00988             MoveNode(pDestNode,Direction);
00989         else
00990             if (pUndoOp->DoMoveNode(this, pDestNode, Direction)==FALSE)
00991                 return FALSE;
00992     }
00993 
00994     // if was selected, reselect to maintain 'parent of selected' flag
00995     if (selected)
00996         SetSelected(TRUE);
00997 
00998     // flag node affected in new position (so parents flagged correctly)
00999     FlagNodeAndDescendantsAffectedAndParentsHaveDescendantAffected();
01000 
01001     return TRUE;
01002 }
01003 
01004 
01005 /********************************************************************************************
01006 >   void VisibleTextNode::ScrollToShow()
01007 
01008     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01009     Created:    24/4/95
01010     Purpose:    If this VTN is not fully on the screen then the screen is scrolled so the
01011                 VTN is more visible.
01012 ********************************************************************************************/
01013 
01014 void VisibleTextNode::ScrollToShow()
01015 {
01016 #if !defined(EXCLUDE_FROM_RALPH)
01017     DocView* pDocView = DocView::GetSelected();
01018     Spread* pSpread = FindParentSpread();       
01019 
01020     if (pDocView!=NULL && pSpread!=NULL)
01021     {
01022         DocRect ScreenArea = GetBlobBoundingRect();
01023 
01024         // Get the extent of the current view and convert to spread coordinates.
01025         DocRect WorkArea = pDocView->GetDocViewRect(pSpread);
01026         pSpread->DocCoordToSpreadCoord(&WorkArea);
01027 
01028         BOOL Scroll = FALSE;
01029         DocCoord WindowTopLeft;
01030         DocCoord Offset(0,0);       // Amount to offset current TopLeft by
01031     
01032         if (!WorkArea.ContainsRect(ScreenArea))
01033         {
01034             if (WorkArea.Height() > ScreenArea.Height() && WorkArea.Width() > ScreenArea.Width())
01035             {
01036                 const double Shift = 0.05;
01037 
01038                 if (ScreenArea.hi.y > WorkArea.hi.y)
01039                     Offset.y = ScreenArea.hi.y-WorkArea.hi.y + (INT32)(WorkArea.Height()*Shift);
01040 
01041                 if (ScreenArea.lo.y < WorkArea.lo.y)
01042                     Offset.y = ScreenArea.lo.y-WorkArea.lo.y - (INT32)(WorkArea.Height()*Shift);
01043 
01044                 if (ScreenArea.hi.x > WorkArea.hi.x)
01045                     Offset.x = ScreenArea.hi.x-WorkArea.hi.x + (INT32)(WorkArea.Width()*Shift);
01046 
01047                 if (ScreenArea.lo.x < WorkArea.lo.x)
01048                     Offset.x = ScreenArea.lo.x-WorkArea.lo.x - (INT32)(WorkArea.Width()*Shift);
01049 
01050                 if (Offset != DocCoord(0,0))
01051                 {
01052                     Scroll = TRUE;
01053                     WindowTopLeft = DocCoord(WorkArea.lo.x, WorkArea.hi.y) + Offset;
01054                 }
01055             }
01056             else
01057             {
01058                 // Cannot contain object on screen.  Centre it.
01059                 Scroll = TRUE;
01060                 DocCoord CentreOfObject((ScreenArea.lo.x+ScreenArea.hi.x)/2, (ScreenArea.lo.y+ScreenArea.hi.y)/2);
01061 
01062                 WindowTopLeft = DocCoord(CentreOfObject.x-WorkArea.Width()/2,CentreOfObject.y+WorkArea.Height()/2);
01063             }
01064         }
01065 
01066         // Now scroll to the new position
01067         if (Scroll)
01068         {
01069             // First, ensure that the spread's pasteboard is large enough to include this node
01070             // This is pretty quick if it is big enough.
01071             pSpread->ExpandPasteboardToInclude(GetBoundingRect());
01072 
01073             // Convert the window coordinate from Spread to Document coords...
01074             pSpread->SpreadCoordToDocCoord(&WindowTopLeft);
01075 
01076             // ...and thence to Logical coordinates
01077             WorkCoord WTL = WindowTopLeft.ToWork(pSpread, pDocView);
01078             pDocView->SetScrollOffsets(WTL, TRUE);
01079 
01080             // New stuff added by Will 29/6/95
01081             // Now we have scrolled the View, we need to invalidate the newly visible areas,
01082             // so that any blob rendering knows that the area has a pending redraw.
01083             // If we wait for the Paint message from the OS, then it will be too late.
01084 
01085             // First we get the new extent of the view we just scrolled and convert to spread coordinates.
01086             WorkArea = pDocView->GetDocViewRect(pSpread);
01087             pSpread->DocCoordToSpreadCoord(&WorkArea);
01088 
01089             DocRect Invalid;
01090 
01091             if (Offset.x != 0)
01092             {
01093                 // Get the invalid horizontal scroll rect, by subtracting the x scroll offset
01094                 // from the left or right edge of the screen (depending on which way we scrolled)
01095                 Invalid.lo.x = Offset.x > 0 ? WorkArea.hi.x - Offset.x : WorkArea.lo.x;
01096                 Invalid.lo.y = WorkArea.lo.y;
01097                 Invalid.hi.x = Offset.x > 0 ? WorkArea.hi.x : WorkArea.lo.x - Offset.x;
01098                 Invalid.hi.y = WorkArea.hi.y;
01099 
01100                 // and invalidate it
01101                 pDocView->ForceRedraw(pSpread, Invalid);
01102             }
01103 
01104             if (Offset.y != 0)
01105             {
01106                 // Get the invalid vertical scroll rect, by subtracting the y scroll offset
01107                 // from the top or bottom edge of the screen (depending on which way we scrolled)
01108                 Invalid.lo.x = WorkArea.lo.x;
01109                 Invalid.lo.y = Offset.y > 0 ? WorkArea.hi.y - Offset.y : WorkArea.lo.y;
01110                 Invalid.hi.x = WorkArea.hi.x;
01111                 Invalid.hi.y = Offset.y > 0 ? WorkArea.hi.y : WorkArea.lo.y - Offset.y;
01112 
01113                 // and invalidate it
01114                 pDocView->ForceRedraw(pSpread, Invalid);
01115             }
01116         }
01117     }
01118 #endif
01119 }
01120 
01121 
01122 /********************************************************************************************
01123 >   virtual BOOL VisibleTextNode::CanAttrBeAppliedToMe(CCRuntimeClass* AttrType)
01124 
01125     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01126     Created:    7/6/95
01127     Inputs:     AttrType: The type of the attribute. It is a type, rather than an 
01128                 instance because this function needs to be called from the Localise/Factor out 
01129                 routines which operate on attribute types.
01130 
01131     Returns:    TRUE if an attribute of AttrType can be applied to this object, 
01132                 FALSE otherwise. 
01133 
01134     Purpose:    This fn is not to be confused with RequiresAttrib, it determines if an 
01135                 attribute of type AttrType can be directly applied to this object. The
01136                 object is assumed to Require the attribute. 
01137 
01138                 This function is called by the GetObjectToApplyTo virtual function.
01139                 
01140                 The function returns FALSE if we are trying to apply a line level 
01141                 attribute to a VisibleTextNode. As a result attributes will get applied
01142                 to the parent TextLine object.
01143 ********************************************************************************************/ 
01144 
01145 BOOL VisibleTextNode::CanAttrBeAppliedToMe(CCRuntimeClass* AttrType)
01146 {
01147     return !TextLine::IsAttrTypeLineLevel(AttrType);
01148 }
01149 
01150 
01151 /********************************************************************************************
01152 >   virtual BOOL VisibleTextNode::OnNodePopUp(Spread* pSpread, DocCoord PointerPos, ContextMenu* pMenu)
01153 
01154     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01155     Created:    06/10/95
01156     Inputs:     pSpread     The spread in which things are happening
01157                 PointerPos  The Location of the mouse pointer at the time of the click
01158                 pMenu       The menu to which items should be added
01159     Returns:    BOOL - TRUE if the node claims the click as its own and FALSE if it is
01160                 not interested in the click
01161     Purpose:    Allows the VisibleTextNode to respond to pop up menu clicks on itself.
01162 ********************************************************************************************/
01163 
01164 BOOL VisibleTextNode::OnNodePopUp(Spread* pSpread, DocCoord PointerPos, ContextMenu* pMenu)
01165 {
01166     TextStory* pStory = this->FindParentStory();
01167 
01168     if (pStory!=NULL && pStory->IsSelected())
01169         return pStory->OnNodePopUp(pSpread, PointerPos, pMenu);
01170     else
01171         return FALSE;
01172 }
01173 
01174 
01176 // AbstractTextChar methods
01177 
01178 /********************************************************************************************
01179 >   void AbstractTextChar::Init()
01180 
01181     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
01182     Created:    3/2/96
01183     Purpose:    common init function for constructors
01184 ********************************************************************************************/
01185 
01186 void AbstractTextChar::Init()
01187 {
01188     mCharWidth       = 0;
01189     mCharAdvance     = 0;
01190     mFontAscent      = 0;
01191     mFontDescent     = 0;
01192     mFontSize        = 0;
01193     mBaseLineShift   = 0;
01194     mAttrdCharBounds = DocRect(0,0,0,0);
01195 }
01196 
01197 
01198 /********************************************************************************************
01199 >   AbstractTextChar::AbstractTextChar()
01200 
01201     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01202     Created:    21/12/94
01203     Purpose:    Simple AbstractTextChar constructor, it is required so that SimpleCopy will work.
01204 ********************************************************************************************/
01205 
01206 AbstractTextChar::AbstractTextChar(): VisibleTextNode() // Call the base class
01207 {
01208     Init();
01209 }
01210 
01211 
01212 /********************************************************************************************
01213 >   AbstractTextChar::AbstractTextChar(Node* ContextNode, AttachNodeDirection Direction, 
01214                                        WCHAR ChCode)
01215 
01216     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01217     Created:    21/12/94
01218     Inputs:     ContextNode: Pointer to a node which this node is to be attached to.     
01219         
01220                 Direction: 
01221             
01222                 Specifies the direction in which the node is to be attached to the 
01223                 ContextNode. The values this variable can take are as follows: 
01224                                   
01225                 PREV      : Attach node as a previous sibling of the context node
01226                 NEXT      : Attach node as a next sibling of the context node
01227                 FIRSTCHILD: Attach node as the first child of the context node
01228                 LASTCHILD : Attach node as a last child of the context node  
01229                 
01230                 ChCode: The UNICODE character to store in the TextChar node
01231                                 
01232     Purpose:    The main TextChar constructor
01233 ********************************************************************************************/
01234 
01235 AbstractTextChar::AbstractTextChar(Node* ContextNode, AttachNodeDirection Direction): 
01236     VisibleTextNode(ContextNode, Direction) // call the base class
01237 {
01238     Init();
01239 }
01240 
01241 
01242 /********************************************************************************************
01243 >   Node* AbstractTextChar::SimpleCopy()
01244 
01245     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01246     Created:    21/12/94
01247     Returns:    
01248     Purpose:    Because this is an abstract class, the SimpleCopy method simply causes
01249                 an ERROR3 to go off.
01250 ********************************************************************************************/
01251 
01252 Node* AbstractTextChar::SimpleCopy()
01253 {
01254     ERROR3("Calling abstract classes SimpleCopy");
01255 
01256     // Well I suppose we should do the copy if the call gets into the retail 
01257     AbstractTextChar* NodeCopy = new AbstractTextChar();
01258 
01259     ERROR1IF(NodeCopy==NULL, NULL, _R(IDE_NOMORE_MEMORY)); 
01260 
01261     if (NodeCopy)
01262         CopyNodeContents(NodeCopy);
01263     
01264     return NodeCopy;
01265 }
01266 
01267 
01268 
01269 /***********************************************************************************************
01270 >   void AbstractTextChar::CopyNodeContents(AbstractTextChar* NodeCopy)
01271 
01272     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01273     Created:    28/4/93
01274     Outputs:    A copy of this node
01275     Purpose:    This method copies the node's contents to the node pointed to by NodeCopy.
01276     Errors:     An assertion failure will occur if NodeCopy is NULL
01277 ***********************************************************************************************/
01278 
01279 void AbstractTextChar::CopyNodeContents(AbstractTextChar* NodeCopy)
01280 {
01281     // Ask the base class to do its bit
01282     VisibleTextNode::CopyNodeContents( NodeCopy );
01283 
01284     // copy specifics
01285     NodeCopy->mCharWidth       = mCharWidth;
01286     NodeCopy->mCharAdvance     = mCharAdvance;
01287     NodeCopy->mFontAscent      = mFontAscent;
01288     NodeCopy->mFontDescent     = mFontDescent;
01289     NodeCopy->mFontSize        = mFontSize;
01290     NodeCopy->mBaseLineShift   = mBaseLineShift;
01291     NodeCopy->mAttrdCharBounds = mAttrdCharBounds;
01292 }
01293 
01294 
01295 /***********************************************************************************************
01296 >   void AbstractTextChar::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
01297 
01298     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01299     Created:    18/12/2003
01300     Outputs:    -
01301     Purpose:    Polymorphically copies the contents of this node to another
01302     Errors:     An assertion failure will occur if NodeCopy is NULL
01303     Scope:      protected
01304                                      
01305 ***********************************************************************************************/
01306 
01307 void AbstractTextChar::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
01308 {
01309     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
01310     ENSURE(IS_A(pNodeCopy, AbstractTextChar), "PolyCopyNodeContents given wrong dest node type");
01311 
01312     if (IS_A(pNodeCopy, AbstractTextChar))
01313         CopyNodeContents((AbstractTextChar*)pNodeCopy);
01314 }
01315 
01316 
01317 
01318 /********************************************************************************************
01319 >   String AbstractTextChar::Describe(BOOL Plural, BOOL Verbose = TRUE)            
01320 
01321     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01322     Created:    21/12/94
01323     Inputs:     Plural: Singular or plural description
01324     Returns:    A string describing the node
01325     Purpose:    Gives a description of all character nodes
01326 ********************************************************************************************/
01327 
01328 String AbstractTextChar::Describe(BOOL Plural, BOOL Verbose)           
01329 {
01330     if (Plural)
01331         return(String(_R(IDS_DESCRIBE_TEXTCHARP)));  
01332     else
01333         return(String(_R(IDS_DESCRIBE_TEXTCHARS))); 
01334 }
01335 
01336 
01337 /********************************************************************************************
01338 >   UINT32 AbstractTextChar::GetNodeSize() const 
01339 
01340     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01341     Created:    21/12/94
01342     Returns:    The size of the node in bytes
01343     Purpose:    For finding the size of the node 
01344 ********************************************************************************************/
01345 
01346 UINT32 AbstractTextChar::GetNodeSize() const 
01347 {
01348     ERROR3("Trying to find the size of an AbstractTextChar ?"); 
01349     return (sizeof(AbstractTextChar)); 
01350 }
01351 
01352 
01353 /********************************************************************************************
01354 >   void AbstractTextChar::GetDebugDetails(StringBase* Str) 
01355 
01356     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01357     Created:    1/2/95
01358     Outputs:    Str: String giving debug info about the node
01359     Purpose:    For obtaining debug information about the Node. 
01360                 This fn can be deleted before we ship 
01361 ********************************************************************************************/
01362 
01363 void AbstractTextChar::GetDebugDetails(StringBase* Str)
01364 {
01365     VisibleTextNode::GetDebugDetails(Str);
01366 }
01367 
01368 
01369 /********************************************************************************************
01370 >   virtual DocRect AbstractTextChar::GetBoundingRect(BOOL DontUseAttrs=FALSE, BOOL HitTest=FALSE)
01371 
01372     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
01373     Created:    22/3/94
01374     Inputs:     DontUseAttrs - indicates that bounds of attributes applied to node should be ignored
01375                 Defaults to FALSE
01376                 HitTest      - TRUE if being called during HitTest
01377     Returns:    The characters bounding rect
01378     Purpose:    Gets the bounds of the char
01379                 if the cached bounds are invalid, they are recalculated
01380 ********************************************************************************************/
01381 
01382 DocRect AbstractTextChar::GetBoundingRect(BOOL DontUseAttrs, BOOL HitTest)
01383 {
01384     // if not hit testing, attrs should be included and cache is valid, return cached value
01385     if (HitTest==FALSE && DontUseAttrs==FALSE && IsBoundingRectValid)
01386         return BoundingRectangle;
01387 
01388     BOOL    ok=TRUE;
01389     DocRect TempBounds;
01390     if (HitTest)
01391         ok=GetMetricsRectBounds(&TempBounds);
01392     else
01393     {
01394         // get the matrix to transform the char to the correct point in the doc
01395         Matrix matrix;
01396         ok=GetStoryAndCharMatrix(&matrix);
01397 
01398         // get attr'd-char bounds from node, and transform them
01399         TempBounds=GetAttrdCharBounds();                                              
01400         if (ok) ok=matrix.TransformBounds(&TempBounds);
01401 
01402         // if including attrs, account for line width and recache bounds
01403         NodeAttribute* pAttr;
01404         if (ok && DontUseAttrs==FALSE && FindAppliedAttribute(CC_RUNTIME_CLASS(AttrLineWidth), &pAttr))
01405         {
01406             // get width of line and inflate bounds
01407             LineWidthAttribute* pLineWidthAttr=(LineWidthAttribute*)(pAttr->GetAttributeValue());
01408             TempBounds.Inflate( (MILLIPOINT)(pLineWidthAttr->LineWidth)/2 );
01409 
01410             // update value in cache and flag valid
01411             BoundingRectangle   = TempBounds;
01412             IsBoundingRectValid = TRUE;
01413         }
01414         // now we must also account for brush attributes
01415         NodeAttribute* pBrushAttr = NULL;
01416         if (ok && DontUseAttrs == FALSE && FindAppliedAttribute(CC_RUNTIME_CLASS(AttrBrushType), &pBrushAttr))
01417         {
01418             DocRect BrushRect = ((AttrBrushType*)pBrushAttr)->GetAttrBoundingRect(this);
01419             BoundingRectangle = BoundingRectangle.Union(BrushRect);
01420             IsBoundingRectValid = TRUE;
01421         }
01422     }
01423 
01424     // report any errors which occurred, and return the bounding box
01425     if (!ok) InformError();
01426     return TempBounds;
01427 }
01428 
01429 
01430 /********************************************************************************************
01431 >   DocRect AbstractTextChar::GetBlobBoundingRect()
01432 
01433     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
01434     Created:    2/4/95
01435     Returns:    DocRect - Returns the bounding rect of the char and its blobs
01436     Purpose:    Calculates the blob bounding box of the char based on its metrics
01437                 Irrespective of their visibility
01438 ********************************************************************************************/
01439 
01440 DocRect AbstractTextChar::GetBlobBoundingRect()
01441 {
01442     DocRect Bounds(0,0,0,0);
01443     if (GetMetricsRectBounds(&Bounds)==FALSE)
01444         return GetBoundingRect();
01445 
01446     IncludeChildrensBoundingRects(&Bounds);
01447     return Bounds;
01448 }
01449 
01450 /********************************************************************************************
01451 >   virtual DocRect AbstractTextChar::GetImagemapClickableRectangle()
01452 
01453     Author:     Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com>
01454     Created:    27/3/97
01455     Inputs:     -
01456     Returns:    The bounding rectangle of this character and all adjacent characters
01457                 in the same line with the same Web Address attribute
01458     Purpose:    Used to get the clickable area of this character for an imagemap.
01459 
01460                 The clickable area of this character is defined as the bounding
01461                 rectangle of all adjacent characters with the same Web Address attribute.
01462                 This is so that sequences of characters with the same Web Address attribute
01463                 present a single clickable area, rather than a lot of separate areas.
01464 
01465                 The way it does this is by calling our helper function
01466                 GetImagemapRectForAdjacentChars twice: once to get the
01467                 clickable rectangle of the characters before this, once
01468                 to get the clickable rectangle of the characters after this.
01469 
01470 ********************************************************************************************/
01471 
01472 DocRect AbstractTextChar::GetImagemapClickableRectangle()
01473 {
01474     DocRect rectPrevious=GetImagemapRectForAdjacentChars(FALSE);
01475     DocRect rectNext=GetImagemapRectForAdjacentChars(TRUE);
01476 
01477     rectPrevious=rectPrevious.Union(rectNext);
01478 
01479     return rectPrevious;
01480 }
01481 
01482 /********************************************************************************************
01483 >   virtual DocRect AbstractTextChar::GetImagemapRectForAdjacentChars(BOOL fForwards)
01484 
01485     Author:     Graham_Walmsley (Xara Group Ltd) <camelotdev@xara.com>
01486     Created:    27/3/97
01487     Inputs:     fForwards   TRUE for the characters after this one
01488                             FALSE for the character before this one
01489     Returns:    The bounding rectangle of this character and all characters
01490                 (before/after) this one in this line with the same
01491                 Web Address attribute.
01492 
01493     Purpose:    Called by GetImagemapClickableRectangle to get the clickable rectangle
01494                 for this character and all the adjacent characters with the same
01495                 WebAddress attribute.
01496 
01497     SeeAlso:    AbstractTextChar::GetImagemapClickableRectangle()
01498 
01499 ********************************************************************************************/
01500 
01501 DocRect AbstractTextChar::GetImagemapRectForAdjacentChars(BOOL fForwards)
01502 {
01503     //First set up a pointer to the node we're currently looking at.
01504     //It will start at this text character
01505     //and scan either forwards or backwards
01506     AbstractTextChar* patcLookNode=this;
01507 
01508     //This flag tells us whether we are pointing at a character with
01509     //the same Web Address attribute as this one
01510     BOOL fSameAttribute=TRUE;
01511 
01512     //And this is the DocRect we will return
01513     DocRect rectToReturn=GetBoundingRect(FALSE, TRUE);
01514 
01515     //And let's find the Web Address attribute applied to this character
01516     AttrWebAddress* pwaThisAttribute=NULL;
01517 
01518     FindAppliedAttribute(CC_RUNTIME_CLASS(AttrWebAddress), (NodeAttribute**) &pwaThisAttribute);
01519     
01520     //While the node we're looking at exists, and has the same
01521     //Web Address attribute applied to it as this one
01522     while (patcLookNode && fSameAttribute)
01523     {
01524         //Then get the bounding box of that node
01525         DocRect rectLookNode=patcLookNode->GetBoundingRect(FALSE,TRUE);
01526 
01527         //Expand our rectangle to return to include that bounding box
01528         rectToReturn=rectToReturn.Union(rectLookNode);
01529 
01530         //Then move the pointer either forwards or backwards
01531         if (fForwards)
01532             patcLookNode=patcLookNode->FindNextAbstractTextCharInLine();
01533         else
01534             patcLookNode=patcLookNode->FindPrevAbstractTextCharInLine();
01535 
01536         //Now, if we are still looking at a node
01537         if (patcLookNode)
01538         {
01539             //Then find the attribute applied to that node
01540             AttrWebAddress* pwaLookAttribute=NULL;
01541 
01542             patcLookNode->FindAppliedAttribute(CC_RUNTIME_CLASS(AttrWebAddress), (NodeAttribute**) &pwaLookAttribute);
01543             ERROR2IF(pwaLookAttribute==NULL, DocRect(0,0,0,0), "AbstractTextChar::GetImagemapRectForAdjacentChars got no applied attribute!");
01544         
01545             //And test whether it's the same as the attribute applied to this node
01546             fSameAttribute=(*pwaLookAttribute==*pwaThisAttribute);
01547         }
01548     }
01549 
01550     //Then return the rectangle we've created
01551     return rectToReturn;
01552 }
01553 
01554 
01555 /********************************************************************************************
01556 >   void AbstractTextChar::RenderObjectBlobs(RenderRegion* pRenderRegion)
01557 
01558     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
01559     Created:    2/4/95
01560     Inputs:     pRenderRegion - region to render the blobs into
01561     Purpose:    Renders the selection blobs
01562 ********************************************************************************************/
01563 
01564 void AbstractTextChar::RenderObjectBlobs(RenderRegion* pRenderRegion)
01565 {
01566 #if !defined(EXCLUDE_FROM_RALPH)
01567     Path* pPath=CreateMetricsRectPath();
01568     if (pPath!=NULL && pRenderRegion!=NULL)
01569     {
01570         DocColour Trans(COLOUR_TRANS);
01571         pRenderRegion->SetLineWidth(0);
01572         pRenderRegion->SetLineColour(Trans);
01573         pRenderRegion->SetFillColour(COLOUR_UNSELECTEDBLOB);
01574         pRenderRegion->DrawPath(pPath);
01575         delete pPath;
01576     }
01577 #endif
01578 }
01579 
01580 
01581 /********************************************************************************************
01582 >   void AbstractTextChar::RenderTinyBlobs(RenderRegion* pRenderRegion)
01583 
01584     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01585     Created:    3/4/95
01586     Inputs:     pRenderRegion - region to render the blobs into
01587     Purpose:    Renders the tiny blob, which is an outline selection box
01588 ********************************************************************************************/
01589 
01590 void AbstractTextChar::RenderTinyBlobs(RenderRegion* pRenderRegion)
01591 {
01592 #if !defined(EXCLUDE_FROM_RALPH)
01593     Path* pPath=CreateMetricsRectPath();
01594     if (pPath!=NULL && pRenderRegion!=NULL)
01595     {
01596         DocColour Trans(COLOUR_TRANS);
01597         pRenderRegion->SetLineColour(COLOUR_UNSELECTEDBLOB);
01598         pRenderRegion->SetFillColour(Trans);
01599         pRenderRegion->DrawPath(pPath);
01600         delete pPath;
01601     }
01602 #endif
01603 }
01604 
01605 
01606 /********************************************************************************************
01607 >   BOOL AbstractTextChar::GetMetricsRect(DocRect* pRect)
01608 
01609     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
01610     Created:    3/4/95
01611     Outputs     pRect - 
01612     Returns:    FALSE if fails
01613     Purpose:    return the metrics rect of a char
01614 ********************************************************************************************/
01615 
01616 BOOL AbstractTextChar::GetMetricsRect(DocRect* pRect)
01617 {
01618     ERROR2IF(pRect==NULL,FALSE,"AbstractTextChar::GetMetricsRect() - pRect==NULL");
01619 
01620     TextLine* pTextLine=(TextLine*)FindParent();
01621     ERROR2IF(pTextLine==NULL,FALSE,"AbstractTextChar::GetMetricsRect - pTextLine==NULL");
01622 
01623     // get a rect (relative to the TextStory) from the bottom left to top right of the char
01624     pRect->lo.y = pTextLine->GetLineDescent();
01625     pRect->hi.y = pTextLine->GetLineAscent();
01626     pRect->lo.x = 0;
01627     pRect->hi.x = 0;
01628     MILLIPOINT advance=GetVisibleAdvance();
01629     if (advance>=0)
01630         pRect->hi.x = advance;
01631     else
01632         pRect->lo.x = advance;
01633 
01634     return TRUE;
01635 }
01636 
01637 
01638 /********************************************************************************************
01639 >   BOOL AbstractTextChar::GetMetricsRectInStory(DocRect* pRect)
01640 
01641     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
01642     Created:    3/4/95
01643     Outputs     pRect - 
01644     Returns:    FALSE if fails
01645     Purpose:    return the metrics rect of a char relative to the TextStory
01646     Note:       Not valid for text on a path!!
01647 ********************************************************************************************/
01648 
01649 BOOL AbstractTextChar::GetMetricsRectInStory(DocRect* pRect)
01650 {
01651     ERROR2IF(pRect==NULL,FALSE,"AbstractTextChar::GetMetricsRectInStory() - pRect==NULL");
01652 
01653     if (GetMetricsRect(pRect)==FALSE)
01654         return FALSE;
01655 
01656     // make it relative to the story!
01657     GetpMatrix()->transform((Coord*)&(pRect->lo),2);
01658 
01659     return TRUE;
01660 }
01661 
01662 
01663 /********************************************************************************************
01664 >   BOOL AbstractTextChar::GetMetricsRectBounds(DocRect* pRect)
01665 
01666     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
01667     Created:    3/4/95
01668     Outputs     pRect - 
01669     Returns:    FALSE if fails
01670     Purpose:    return the bounds in the doc of the char's metrics rect
01671 ********************************************************************************************/
01672 
01673 BOOL AbstractTextChar::GetMetricsRectBounds(DocRect* pRect)
01674 {
01675     ERROR2IF(pRect==NULL,FALSE,"AbstractTextChar::GetMetricsRectInStory() - pRect==NULL");
01676 
01677     Matrix matrix;
01678     if (GetStoryAndCharMatrix(&matrix)==FALSE)
01679         return FALSE;
01680 
01681     if (GetMetricsRect(pRect)==FALSE)
01682         return FALSE;
01683 
01684     if (matrix.TransformBounds(pRect)==FALSE)
01685         return FALSE;
01686 
01687     return TRUE;
01688 }
01689 
01690 
01691 /********************************************************************************************
01692 >   Path* AbstractTextChar::CreateMetricsRectPath()
01693 
01694     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
01695     Created:    19/3/95
01696     Returns:    pointer to path (or NULL if fails)
01697     Purpose:    creates a rectangular path the advance width of a char and
01698                 the height of a line transformed to the correct point in the doc
01699 ********************************************************************************************/
01700 
01701 Path* AbstractTextChar::CreateMetricsRectPath()
01702 {
01703     DocRect rect(0,0,0,0);
01704     if (GetMetricsRect(&rect)==FALSE)
01705         return FALSE;
01706 
01707     // create the path
01708     Path* pBoundsPath=new Path(); 
01709     BOOL ok=(pBoundsPath!=NULL);
01710     if (ok) ok=pBoundsPath->Initialise(6,12);
01711     if (ok) ok=pBoundsPath->AddMoveTo(rect.lo);
01712     if (ok) ok=pBoundsPath->AddLineTo(DocCoord(rect.hi.x,rect.lo.y));   // bottom line
01713     if (ok) ok=pBoundsPath->AddLineTo(rect.hi);                     // right side
01714     if (ok) ok=pBoundsPath->AddLineTo(DocCoord(rect.lo.x,rect.hi.y));   // top line
01715     if (ok) ok=pBoundsPath->AddLineTo(rect.lo);                     // left side
01716     if (ok) ok=pBoundsPath->CloseSubPath();
01717     if (ok) pBoundsPath->IsFilled=TRUE;
01718 
01719     // transform path to correct point in doc
01720     Matrix matrix;
01721     if (ok) ok=GetStoryAndCharMatrix(&matrix);
01722     DocCoord* pPathCoords=NULL;
01723     if (ok) pPathCoords=pBoundsPath->GetCoordArray();                                
01724     if (ok) ok=(pPathCoords!=NULL);
01725     if (ok) matrix.transform((Coord*)pPathCoords, pBoundsPath->GetNumCoords());
01726 
01727     // if not OK, delete path and set return path pointer to NULL
01728     if (!ok)
01729     {
01730         delete pBoundsPath;
01731         pBoundsPath=NULL;
01732     }
01733 
01734     return pBoundsPath;
01735 }
01736 
01737 /********************************************************************************************
01738 >   BOOL AbstractTextChar::ReCacheMetrics(FormatRegion* pFormatRegion)
01739 
01740     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
01741     Created:    2/2/96
01742     Inputs:     pFormatRegion - 
01743     Returns:    FALSE if fails
01744     Purpose:    Recache metrics (and AttrdCharBound) in AbstractTextChars
01745 ********************************************************************************************/
01746 
01747 BOOL AbstractTextChar::ReCacheMetrics(FormatRegion* pFormatRegion)
01748 {
01749 #ifndef DISABLE_TEXT_RENDERING
01750     // get metrics for this char with current attribute stack
01751     CharMetrics metrics;
01752     if (pFormatRegion->GetCharMetrics(&metrics,GetUnicodeValue())==FALSE)
01753         return FALSE;
01754 
01755     // set font ascent, descent and size
01756     SetFontAscent( metrics.FontAscent);
01757     SetFontDescent(metrics.FontDescent);
01758     SetFontSize(pFormatRegion->GetFontSize());
01759     SetBaseLineShift(pFormatRegion->GetBaseLineShift());
01760 
01761     // set char width and advance width inc tracking ...
01762     if (IS_A(this,KernCode))
01763     {
01764         INT32       KernInEmBy1000 = ((KernCode*)this)->GetValue().x;
01765         MILLIPOINT KernInMP       = MulDiv(KernInEmBy1000, metrics.FontEmWidth, 1000);
01766         SetCharWidth(KernInMP);
01767         SetCharAdvance(GetCharWidth());
01768     }
01769     else if (IS_A(this,HorizontalTab))
01770     {
01771         /* tab widths are not dependent on attributes, so do not do anything */
01772     }
01773     else if (this->IsAnEOLNode())
01774     {
01775         SetCharWidth(0);
01776         SetCharAdvance(0);
01777     }
01778     else
01779     {
01780         SetCharWidth(metrics.CharWidth);
01781         MILLIPOINT TrackingInMP       = 0;
01782         MILLIPOINT TrackingInEmBy1000 = pFormatRegion->GetTracking();
01783         if (TrackingInEmBy1000 !=0 )
01784             TrackingInMP = MulDiv(TrackingInEmBy1000, metrics.FontEmWidth, 1000);
01785 
01786         TextStory *story = FindParentStory();
01787         if (story)
01788         {
01789             if (story->IsAutoKerning())
01790                 SetCharAdvance(GetCharWidth()+TrackingInMP+GetAutoKernSize(pFormatRegion));
01791             else
01792                 SetCharAdvance(GetCharWidth()+TrackingInMP);
01793         }
01794         else
01795             ERROR3("Can't find base story");
01796     }
01797 
01798     // set AttrdCharBounds (if zero size (or kern code), set to sensible size for hit test)
01799     DocRect AttrdCharBounds(0,0,0,0);
01800     if (!IS_A(this,KernCode) && !IS_A(this,HorizontalTab))
01801         if (pFormatRegion->GetAttrdCharBounds(&AttrdCharBounds,GetUnicodeValue())==FALSE)
01802             return FALSE;
01803     if (AttrdCharBounds.IsEmpty())
01804         AttrdCharBounds.hi = DocCoord(GetCharAdvance(),pFormatRegion->GetFontSize()/3);
01805     SetAttrdCharBounds(AttrdCharBounds);
01806 #endif
01807     return TRUE;
01808 }
01809 
01810 
01811 /********************************************************************************************
01812 >   MILLIPOINT AbstractTextChar::GetVisibleAdvance()
01813 
01814     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
01815     Created:    16/4/95
01816     Returns:    pointer to path (or NULL if fails)
01817     Purpose:    get the visible advance with of the char
01818                 ie advance width less last char tracking if at end of line
01819 ********************************************************************************************/
01820 
01821 MILLIPOINT AbstractTextChar::GetVisibleAdvance()
01822 {
01823     if (IS_A(this,TextChar) && FindNext(CC_RUNTIME_CLASS(AbstractTextChar))==NULL)
01824          return GetCharWidth();
01825 
01826     return GetCharAdvance();
01827 }
01828 
01829 
01831 // TextChar methods
01832 
01833 /********************************************************************************************
01834 >   TextChar::TextChar()
01835 
01836     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01837     Created:    21/12/94
01838     Purpose:    Simple TextChar constructor, it is required so that SimpleCopy will work.
01839                 You should not normally call this constructor as it does not initialise
01840                 the object.
01841 ********************************************************************************************/
01842 
01843 TextChar::TextChar(): AbstractTextChar()
01844 {
01845     Ch = _T('\0'); 
01846 }
01847 
01848  
01849 /********************************************************************************************
01850 >   TextChar::TextChar(Node* ContextNode, AttachNodeDirection Direction)
01851 
01852     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01853     Created:    21/12/94
01854     Inputs:     ContextNode: Pointer to a node which this node is to be attached to.     
01855         
01856                 Direction: 
01857             
01858                 Specifies the direction in which the node is to be attached to the 
01859                 ContextNode. The values this variable can take are as follows: 
01860                                   
01861                 PREV      : Attach node as a previous sibling of the context node
01862                 NEXT      : Attach node as a next sibling of the context node
01863                 FIRSTCHILD: Attach node as the first child of the context node
01864                 LASTCHILD : Attach node as a last child of the context node                  
01865 
01866     Purpose:    The main TextChar constructor
01867 ********************************************************************************************/
01868 
01869 TextChar::TextChar(Node* ContextNode, AttachNodeDirection Direction, 
01870                    WCHAR ChCode): AbstractTextChar(ContextNode, Direction)
01871 {
01872     Ch = ChCode; 
01873 }
01874 
01875 
01876 /********************************************************************************************
01877 >   Node* TextChar::SimpleCopy()
01878 
01879     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01880     Created:    21/12/94
01881     Returns:    A copy of the node, or NULL if we are out of memory 
01882     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
01883                 The function is virtual, and must be defined for all derived classes of Node  
01884     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of memory
01885                 error and the function returns NULL. 
01886 ********************************************************************************************/
01887 
01888 Node* TextChar::SimpleCopy()
01889 {
01890     // Make a new BigChar and then copy things into it
01891     TextChar* NodeCopy = new TextChar();
01892 
01893     ERROR1IF(NodeCopy==NULL, NULL, _R(IDE_NOMORE_MEMORY)); 
01894 
01895     if (NodeCopy)
01896         CopyNodeContents(NodeCopy);
01897     
01898     return NodeCopy;
01899 }
01900 
01901 
01902 /***********************************************************************************************
01903 >   void TextChar::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
01904 
01905     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01906     Created:    18/12/2003
01907     Outputs:    -
01908     Purpose:    Polymorphically copies the contents of this node to another
01909     Errors:     An assertion failure will occur if NodeCopy is NULL
01910     Scope:      protected
01911                                      
01912 ***********************************************************************************************/
01913 
01914 void TextChar::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
01915 {
01916     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
01917     ENSURE(IS_A(pNodeCopy, TextChar), "PolyCopyNodeContents given wrong dest node type");
01918 
01919     if (IS_A(pNodeCopy, TextChar))
01920         CopyNodeContents((TextChar*)pNodeCopy);
01921 }
01922 
01923 
01924 
01925 /***********************************************************************************************
01926 >   void TextChar::CopyNodeContents(TextChar* NodeCopy)
01927 
01928     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01929     Created:    28/4/93
01930     Outputs:    A copy of this node
01931     Purpose:    This method copies the node's contents to the node pointed to by NodeCopy.
01932     Errors:     An assertion failure will occur if NodeCopy is NULL
01933 ***********************************************************************************************/
01934 
01935 void TextChar::CopyNodeContents(TextChar* NodeCopy)
01936 {
01937     // Ask the base class to do its bit
01938     AbstractTextChar::CopyNodeContents( NodeCopy );
01939     // Copy the rest of the data in here
01940     NodeCopy->Ch        = Ch;
01941 }
01942 
01943 
01944 /********************************************************************************************
01945 >   UINT32 TextChar::GetNodeSize() const 
01946 
01947     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01948     Created:    21/12/94
01949     Returns:    The size of the node in bytes
01950     Purpose:    For finding the size of the node 
01951 ********************************************************************************************/
01952 
01953 UINT32 TextChar::GetNodeSize() const 
01954 {
01955     return (sizeof(TextChar)); 
01956 }
01957 
01958 
01959 /********************************************************************************************
01960 >   void TextChar::GetDebugDetails(StringBase* Str) 
01961 
01962     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
01963     Created:    1/2/95
01964     Outputs:    Str: String giving debug info about the node
01965     Purpose:    For obtaining debug information about the Node. 
01966                 This fn can be deleted before we ship 
01967 ********************************************************************************************/
01968 
01969 void TextChar::GetDebugDetails(StringBase* Str)
01970 {
01971 #ifdef _DEBUG
01972     AbstractTextChar::GetDebugDetails(Str);
01973     String_256 TempStr;
01974         
01975     TempStr._MakeMsg( TEXT( "\r\nUnicode Ch code = #1%u ('#2%c')"),Ch, (Ch<256) ? Ch : ' ' );
01976     (*Str) += TempStr;
01977 #endif
01978 }
01979 
01980 
01981 /********************************************************************************************
01982 >   virtual void TextChar::Render(RenderRegion* pRenderRegion)
01983 
01984     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
01985     Created:    19/3/95
01986     Inputs:     pRenderRegion - RenderRegion with current attributes stack
01987     Purpose:    render a TextChar with the current attributes specified in the RenderRegion
01988 ********************************************************************************************/
01989 
01990 void TextChar::Render(RenderRegion* pRenderRegion)
01991 {
01992     if (RenderCore(pRenderRegion)==FALSE)
01993     {
01994         // Mike 6/10/95: removed this call as it causes big problems if redraw fails
01995         // InformError();
01996     }
01997 }
01998 
01999 
02000 /********************************************************************************************
02001 >   BOOL TextChar::RenderCore(RenderRegion* pRenderRegion)
02002 
02003     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
02004     Created:    19/3/95
02005     Inputs:     pRenderRegion - RenderRegion with current attributes stack
02006     Returns:    FALSE if fails
02007     Purpose:    render a TextChar with the current attributes specified in the RenderRegion
02008 ********************************************************************************************/
02009 
02010 BOOL TextChar::RenderCore(RenderRegion* pRenderRegion)
02011 {
02012 #ifndef DISABLE_TEXT_RENDERING
02013     ERROR2IF(pRenderRegion == NULL, FALSE, "TextChar::RenderCore() - pRenderRegion == NULL");
02014 
02015     // TRACEUSER("wuerthne", _T("TextChar::RenderCore %04x"), GetUnicodeValue());
02016     // If the render region is being used for hit detection then render bounds
02017     // BODGE TEXT - should be in the render region RenderChar function
02018     if (pRenderRegion->IsHitDetect() &&
02019         pRenderRegion->RRQuality.GetLineQuality() != Quality::BlackLine &&
02020         Tool::GetCurrentID() == TOOLID_TEXT)
02021     {
02022         Path* pPath = CreateMetricsRectPath();
02023         ERROR2IF(pPath == NULL, FALSE, "TextChar::RenderCore() - CreateMetricsRectPath() failed");
02024         pRenderRegion->SaveContext();
02025         pRenderRegion->SetFillColour(COLOUR_BLACK);
02026         pRenderRegion->DrawPath(pPath);
02027         pRenderRegion->RestoreContext();
02028         delete pPath;
02029         return TRUE;
02030     }
02031 
02032     Matrix matrix;
02033     if (GetStoryAndCharMatrix(&matrix) == FALSE) return FALSE;
02034 
02035     // render the character through the matrix with current attributes in RenderRegion
02036 
02037     // If the render region is a printing region then maybe print as shapes.
02038     if (pRenderRegion->IsPrinting())
02039     {
02040         PrintControl* pCtrl = pRenderRegion->GetRenderView()->GetPrintControl();
02041         TextStory* pStory = this->FindParentStory();
02042         if ((pCtrl != NULL && pCtrl->GetTextOptions() == PRINTTEXTOPTIONS_ALLTEXTASSHAPES) ||
02043             (pStory != NULL && pStory->IsPrintingAsShapes()))
02044         {
02045             return pRenderRegion->RenderRegion::RenderChar(GetUnicodeValue(), &matrix);
02046         }
02047     }
02048 
02049         // if we're exporting to illustrator, make the text position relative to
02050         // the page.
02051     if (pRenderRegion->IsKindOf (CC_RUNTIME_CLASS(AIEPSRenderRegion)))
02052     {
02053         // (ChrisG 14/12/00) - Only transform if we're not exporting text as shapes, as this
02054         // will be done in CreateCharPath - in AIEPSRenderRegion::RenderChar
02055         if (((AIEPSRenderRegion *) pRenderRegion)->GetTextAsShapes () == FALSE)
02056         {
02057             DocCoord pos;
02058             matrix.GetTranslation(pos);
02059 
02060             Spread* pCurSpread = FindParentSpread();
02061             if (pCurSpread)
02062             {
02063                 DocCoord result;
02064                 pCurSpread->SpreadCoordToPagesCoord(&result, pos);
02065                 matrix.SetTranslation(result);
02066             }
02067         }
02068     }
02069 
02070     // Render into the given region region as characters
02071     BOOL Result =  pRenderRegion->RenderChar(GetUnicodeValue(), &matrix);
02072 
02073 #if EXPORT_TEXT
02074 
02075     // Graeme (27/4/00) - This piece of code is here to fix a problem with the export of
02076     // paragraph text to an EPS varient file. Basically, because only the last line in a
02077     // paragraph is terminated by a line feed, the export filter isn't recognising that
02078     // there is a break, and so all the text appears on one line. This new piece of code
02079     // fixes the problem.
02080 
02081     // This goes horribly wrong if it's printing to distiller, which picks up the paragraph 
02082     // width anyway, making this only relevant for exporting eps files...
02083     if (pRenderRegion->IsPrinting () == FALSE)
02084     {
02085         // Determine whether this is the last node in a text line.
02086         if ( FindNextVTNInLine () == NULL )
02087         {
02088             // Manually output a newline token.
02089             Result = pRenderRegion->WriteNewLine ();
02090         }
02091     }       // if not printing (i.e. doing export)
02092 
02093 #endif  // EXPORT_TEXT
02094 
02095     return Result;
02096 #else
02097     return FALSE;
02098 #endif
02099 }
02100 
02101 
02102 /********************************************************************************************
02103 >   void TextChar::RenderEorDrag(RenderRegion* pRenderRegion)
02104 
02105     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
02106     Created:    27/03/95
02107     Inputs:     pRenderRegion - region to render the blobs into
02108     Purpose:    Renders the selection blobs for this TextChar
02109 ********************************************************************************************/
02110 
02111 void TextChar::RenderEorDrag(RenderRegion* pRenderRegion)
02112 {
02113 #if !defined(EXCLUDE_FROM_RALPH) && !defined(DISABLE_TEXT_RENDERING)
02114     // Before rendering the character we need to render its applied *TEXT* attributes
02115     // into the render region as EOR drag render regions don't maintain an attribute stack
02116     CCAttrMap* pAttribMap = new CCAttrMap(30);
02117     BOOL FoundAttributes = FALSE;
02118     if (pAttribMap)
02119         FoundAttributes = FindAppliedAttributes(pAttribMap);
02120     
02121     if (FoundAttributes)
02122     {
02123         pRenderRegion->SaveContext();
02124         // Render the text attributes
02125         CCAttrMap::iterator pos = pAttribMap->GetStartPosition();
02126         CCAttrMap::iterator end = pAttribMap->GetEndPosition();
02127     
02128         while (pos != end)
02129         {
02130             CCRuntimeClass *pKey;
02131             void           *pVal;
02132             pAttribMap->GetNextAssoc(pos, pKey, pVal);
02133 
02134             if (((NodeAttribute*)pVal)->IsKindOfTextAttribute())
02135                 ((NodeAttribute*)pVal)->Render(pRenderRegion);
02136         }
02137     }
02138 
02139     // Render the character
02140     if (RenderCore(pRenderRegion)==FALSE)
02141         InformError();
02142 
02143     if (FoundAttributes)
02144         pRenderRegion->RestoreContext();
02145 
02146     if (pAttribMap!=NULL) delete pAttribMap;
02147 #endif
02148 }
02149 
02150 /********************************************************************************************
02151 
02152 >   virtual BOOL TextChar::ExportRender ( RenderRegion *pRegion )
02153 
02154     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
02155     Created:    13/10/99
02156     Inputs:     pRegion - A pointer to a RenderRegion.
02157     Outputs:    -
02158     Returns:    TRUE if the RenderRegion is a FlashRenderRegion, otherwise FALSE.
02159     Purpose:    If pRenderRegion points to a FlashRenderRegion, the character will be
02160                 processed as a Flash character, and ultimately stored in the export file
02161                 in the appropriate manner. (As a set of three records: One referring to
02162                 the paths, one mapping the paths onto characters, and one detailling the
02163                 text string itself.
02164 
02165 ********************************************************************************************/
02166 
02167 BOOL TextChar::ExportRender ( RenderRegion *pRegion )
02168 {
02169     BOOL bResult = FALSE;
02170 
02171     // If the RenderRegion is a FlashRenderRegion, use custom Flash export code.
02172     if ( pRegion->IsKindOf ( CC_RUNTIME_CLASS ( FlashRenderRegion ) ) )
02173     {
02174         // Step 1:  Cast the pRegion pointer to be a FlashRenderRegion pointer, so that
02175         //          it can access the custom Flash export methods.
02176         FlashRenderRegion *pFlash = ( FlashRenderRegion* ) pRegion;
02177 
02178         // Step 1a: If the character supports fill or line types that are unsupported by
02179         //          Flash, return FALSE, and export them as paths.
02180         // (Option, may add later.)
02181 
02182         // Step 2:  Pass the character into the appropriate method to export the character.
02183         //          This is where all the hard work is done.
02184         bResult = pFlash->ExportCharacter ( this );
02185     }
02186 
02187     // Step 3:  The export has been done successfully. Return TRUE to prevent Camelot
02188     //          from rendering the character out as paths as well as text. (If there's
02189     //          been an error, bResult will have been set to FALSE.)
02190     return bResult;
02191 }
02192 
02193 /********************************************************************************************
02194 >   BOOL TextChar::CreateNodePath(NodePath** ppNodePath, FormatRegion* pFormatRegion)
02195 
02196     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
02197     Created:    30/3/95
02198     Inputs:     pFormatRegion - format region with current attr stack
02199     Outputs:    ppNodePath    -  pointer to NodePath (may be NULL if none - eg a space!)
02200     Returns:    FALSE if fails
02201     Purpose:    Transforms the TextChar into a NodePath
02202 ********************************************************************************************/
02203 
02204 BOOL TextChar::CreateNodePath(NodePath** ppNodePath, FormatRegion* pFormatRegion)
02205 {
02206 #ifndef DISABLE_TEXT_RENDERING
02207     ERROR2IF(pFormatRegion==NULL,FALSE,"TextChar::CreateNodePath() - pFormatRegion==NULL");
02208     ERROR2IF(   ppNodePath==NULL,FALSE,"TextChar::CreateNodePath() - ppNodePath==NULL");
02209 
02210     // get the char's path transformed to the correct place inthe doc
02211     Matrix matrix;
02212     if (GetStoryAndCharMatrix(&matrix)==FALSE)
02213         return FALSE;
02214     Path* pPath=pFormatRegion->CreateCharPath(GetUnicodeValue(), &matrix);
02215     if (pPath==NULL)
02216         return FALSE;
02217     pPath->InitialiseFlags();
02218 
02219     // Allocate a new NodePath node and copy path data into it
02220     BOOL ok=TRUE;
02221     NodePath* pNodePath=NULL;
02222     if (pPath->GetNumCoords()!=0)
02223     {
02224         pNodePath=new NodePath;
02225         ok=(pNodePath!=NULL);
02226         if (ok) ok=pNodePath->InkPath.Initialise(pPath->GetNumCoords(),1);
02227         if (ok) ok=pNodePath->InkPath.CopyPathDataFrom(pPath);
02228         if (!ok)
02229         {
02230             delete pNodePath;
02231             pNodePath=NULL;
02232         }
02233     }
02234 
02235     delete pPath;
02236 
02237     *ppNodePath=pNodePath;
02238     return ok;
02239 #else
02240     return FALSE;
02241 #endif
02242 }
02243 
02244 
02245 
02246 /***********************************************************************************************
02247 >   virtual BOOL TextChar::Snap(DocCoord* pDocCoord)
02248 
02249     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
02250     Created:    19/10/95
02251     Inputs:     pDocCoord   = a coord in Spread coords
02252     Outputs:    If the point is snapped then pDocCoord will contain the point of attraction.
02253     Returns:    TRUE    - the DocCoord has been snapped to the character's path.
02254                 FALSE   - the DocCoord has not been processed.
02255     Purpose:    Snaps to given coord to the nearest point on the characters render path.  If
02256                 it is not appropriate to snap the coord to the shape (at the moment this means
02257                 the coord is too far awawy), then FALSE is returned.
02258 **********************************************************************************************/
02259 
02260 BOOL TextChar::Snap(DocCoord* pDocCoord)
02261 {
02262     BOOL Snapped = FALSE;
02263 
02264 #if !defined(EXCLUDE_FROM_RALPH)
02265 //  MILLIPOINT SnapDist    = CSnap::GetSnapDist();
02266 //  MILLIPOINT SqrSnapDist = SnapDist*SnapDist;
02267 
02268     // create a format region with an attribute stack
02269     FormatRegion FRegion;
02270     FormatRegion* pFormatRegion=&FRegion;
02271     BOOL ok = pFormatRegion->Init(this);
02272     pFormatRegion->SaveContext();
02273 
02274     // Get the path for this character
02275     NodePath* pPath = NULL;
02276     if (ok)
02277         ok = CreateNodePath(&pPath, pFormatRegion);
02278 
02279     if (ok && (pPath!= NULL) && (pPath->InkPath.GetNumCoords() > 0))
02280     {
02281         Snapped = CSnap::SnapCoordToPath(pDocCoord, &(pPath->InkPath));
02282         delete pPath;
02283     }
02284 
02285     pFormatRegion->RestoreContext();
02286 #endif
02287     return Snapped;
02288 }
02289 
02290 
02291 /********************************************************************************************
02292 >   virtual BOOL TextChar::SupportsClipboardFormat(InternalClipboardFormat *Format) const
02293 
02294     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02295     Created:    26/4/95
02296     Returns:    TRUE  = This node supports the given format
02297                 FALSE = This node does not support the format (or the format is unknown)
02298 
02299     Purpose:    Determine if a node supports a given internal data type. This is used
02300                 by the clipboard when exporting to other applications in order to
02301                 determine if certain data types can be supplied.
02302 
02303                 e.g. The basic formats include:
02304                     Vector      - this is ALWAYS assumed to be available (Vector format
02305                                   includes every Node, e.g. export in Camelot .art format)
02306 
02307                     Text        - As well as paths, some objects can provide text chars
02308 
02309                     Bitmap      - Bitmap fills can render a filled object or supply the
02310                                   bitmap used for filling with.
02311 
02312                 See InternalClipboardFormat (kernel\cliptype.h) for more details
02313 
02314     Notes:      TextChars can be exported as either "vector" or "text" data
02315     SeeAlso:    InternalClipboardFormat; Node::SupportsClipboardFormat
02316 ********************************************************************************************/
02317 
02318 BOOL TextChar::SupportsClipboardFormat(InternalClipboardFormat *Format) const
02319 {
02320 #if !defined(EXCLUDE_FROM_RALPH)
02321     // TextChars can be exported as either "vector" or "text" data
02322     InternalClipboardFormat textformat(CLIPTYPE_TEXT);
02323     return(Format->IsSameFormat(textformat));
02324 #else
02325     return FALSE;
02326 #endif
02327 }
02328 
02329 /********************************************************************************************
02330 
02331 >   BOOL TextChar::WritePreChildrenWeb(BaseCamelotFilter *pFilter)
02332     BOOL TextChar::WritePreChildrenNative(BaseCamelotFilter *pFilter)
02333 
02334     Author:     Andy_Hayward (Xara Group Ltd) <camelotdev@xara.com>
02335     Created:    10/07/96
02336     Inputs:     pFilter - new file format filter to write record to
02337     Returns:    TRUE if successful, FALSE otherwise
02338     Purpose:    Writes a text char record to the new file format filter
02339 
02340 ********************************************************************************************/
02341 
02342 BOOL TextChar::WritePreChildrenWeb(BaseCamelotFilter *pFilter)
02343 {
02344 #ifdef DO_EXPORT
02345     return CXaraFileTxtChar::WritePreChildrenWeb(pFilter, this);
02346 #else
02347     return FALSE;
02348 #endif
02349 }
02350 
02351 BOOL TextChar::WritePreChildrenNative(BaseCamelotFilter *pFilter)
02352 {
02353 #ifdef DO_EXPORT
02354     return CXaraFileTxtChar::WritePreChildrenNative(pFilter, this);
02355 #else
02356     return FALSE;
02357 #endif
02358 }
02359 
02360 /********************************************************************************************
02361 
02362 >   BOOL TextChar::WritePostChildrenWeb(BaseCamelotFilter* pFilter)
02363 
02364     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02365     Created:    14/8/96
02366     Inputs:     pFilter - new file format filter to write record to
02367     Returns:    TRUE if successful, FALSE otherwise
02368     Purpose:    Tells the text node that all it's children have been exported (or skipped if
02369                 CanWriteChildrenWeb() returned FALSE)
02370 
02371                 Chars use this to reset their AlreadyWritten flag, because this can only be reset
02372                 after it's children have been skipped
02373 
02374 ********************************************************************************************/
02375 
02376 BOOL TextChar::WritePostChildrenWeb(BaseCamelotFilter* pFilter)
02377 {
02378     SetAlreadyWritten(FALSE);
02379     return TRUE;
02380 }
02381 
02382 //------------------------------------------------------------------------------
02383 // See TextChar::WritePostChildrenWeb(BaseCamelotFilter *pFilter) for more details
02384 
02385 BOOL TextChar::WritePostChildrenNative(BaseCamelotFilter* pFilter)
02386 {
02387     SetAlreadyWritten(FALSE);
02388     return TRUE;
02389 }
02390 
02391 /********************************************************************************************
02392 
02393 >   BOOL TextChar::CanWriteChildrenWeb(BaseCamelotFilter *pFilter)
02394 
02395     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
02396     Created:    14/8/96
02397     Inputs:     pFilter - new file format filter to write record to
02398     Returns:    TRUE if successful, FALSE otherwise
02399     Purpose:    Asks if it's alright to write out the char's children
02400 
02401                 Chars will only say no if they've already been written out (checks the AlreayWritten flag)
02402 
02403 ********************************************************************************************/
02404 
02405 BOOL TextChar::CanWriteChildrenWeb(BaseCamelotFilter *pFilter)
02406 {
02407     return !AlreadyWritten();
02408 }
02409 
02410 //------------------------------------------------------------------------------
02411 // See TextChar::CanWriteChildrenWeb(BaseCamelotFilter *pFilter) for more details
02412 
02413 BOOL TextChar::CanWriteChildrenNative(BaseCamelotFilter *pFilter)
02414 {
02415     return !AlreadyWritten();
02416 }
02417 
02418 /********************************************************************************************
02419 
02420 >   MILLIPOINT TextChar::GetAutoKernSize(FormatRegion* pFormatRegion)
02421 
02422     Author:     Jonathan_Payne (Xara Group Ltd) <camelotdev@xara.com>
02423     Created:    17/10/2000
02424     Inputs:     FormatRegion
02425     Returns:    Kern between char and next char
02426     Purpose:    Find auto kern between two TextChar and next TextChar in the story
02427 
02428 ********************************************************************************************/
02429 MILLIPOINT TextChar::GetAutoKernSize(FormatRegion* pFormatRegion)
02430 {
02431     TextChar* pNextTC = FindNextTextCharInStory();
02432 
02433     if (pNextTC)
02434     {
02435         // If we get here, we know there is a TextChar (this) and a following textchar (pNextTC)
02436         // that might have a kern between them.  Before asking for that kerning value, we have
02437         // to check that both 'this' and 'pNextTC' are of the same font and have the same bold/
02438         // italic attribs.  If we did not do this, GetCharsKerning would use the font currently
02439         // selected into pFormatRegion which is just the font the TextChar 'this'.
02440 
02441         // The basic method I am using to do this is to look at the child attribs of 'this'
02442         // (don't care about attribs higher up the tree as they will apply to both 'this' and
02443         // 'pNextTC') and check that pNextTC also has child attribs of the same type.
02444 
02445         // Well it should work...
02446 
02447         // Hopefully...
02448 
02449         Node *Child;            // used to point to child attribs of 'this'
02450         Node *CompareChild;     // used to point to child attribs of 'pNextTC'
02451 
02452         Child = FindFirstChild();
02453         while (Child)
02454         {
02455             if (IS_A(Child,AttrTxtFontTypeface) ||
02456                 IS_A(Child,AttrTxtItalic)       ||
02457                 IS_A(Child,AttrTxtBold)         ||
02458                 IS_A(Child,AttrTxtFontSize)     ||
02459                 IS_A(Child,AttrTxtScript))
02460             {
02461                 // 'this' has a child node that could mean it has a difference between
02462                 // it 'pNextTC' that could be important to us.  Now we have to find out firstly
02463                 // 'pNextTC' has this child node and if so if it has the same value.
02464                 CompareChild = pNextTC->FindFirstChild();
02465                 while (CompareChild && Child->GetRuntimeClass() != CompareChild->GetRuntimeClass())
02466                     CompareChild = CompareChild->FindNext();
02467 
02468                 if (CompareChild)
02469                 {
02470                     // If we get here we have found an attrib that is shared by 'this' and 'pNextTC'
02471                     // with 'Child' pointing to the attrib of 'this' and 'CompareChild' pointing to the
02472                     // attrib of 'pNextTC'.
02473                     if (Child->IsDifferent(CompareChild))
02474                         return 0; // No kern
02475                 }
02476                 else
02477                 {
02478                     // We found an attrib on 'this' but not on 'pNextTC' so they must be different.
02479                     // That means that we don't kern.
02480                     return 0; // No kern
02481                 }
02482             }
02483             
02484             Child = Child->FindNext();
02485         }
02486 
02487         // If we get here, we know that 'this' has no attribs that are different from 'pNextTC'.
02488         // What we don't know is if 'pNextTC' has an attrib that 'this' does not have.  This case
02489         // is made a little simpler as the mere existence of an attrib should be enough to make the
02490         // two different so there is no need to compare the attrib values.
02491         CompareChild = pNextTC->FindFirstChild();
02492         while (CompareChild)
02493         {
02494             if (IS_A(CompareChild,AttrTxtFontTypeface)  ||
02495                 IS_A(CompareChild,AttrTxtItalic)        ||
02496                 IS_A(CompareChild,AttrTxtBold)          ||
02497                 IS_A(CompareChild,AttrTxtFontSize)      ||
02498                 IS_A(CompareChild,AttrTxtScript))
02499             {
02500                 // Found an attrib of 'pNextTC'.  Just need to check that 'this' has this attrib as well
02501                 // (if it does have that attrib, we will have checked they are the same in the IsDifferent()
02502                 // call, above).
02503                 Child = FindFirstChild();
02504                 while (Child && Child->GetRuntimeClass() != CompareChild->GetRuntimeClass())
02505                     Child = Child->FindNext();
02506 
02507                 if (!Child)
02508                     return 0; // No kern
02509             }
02510 
02511             CompareChild = CompareChild->FindNext();
02512         }
02513 
02514         // Wow, we got through all the tests so I guess we might as well check for a kern now
02515         // (at last).  Possible optimisation - we could do this at the top of the function and
02516         // then do all the all the checking afterwards - not sure if this would be faster or not.
02517         return pFormatRegion->GetCharsKerning(GetUnicodeValue(), pNextTC->GetUnicodeValue());
02518     }
02519     else
02520         return 0; // No kern
02521 }
02522 
02524 // CaretNode methods
02525 
02526 /********************************************************************************************
02527 >   CaretNode::CaretNode()
02528 
02529     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
02530     Created:    21/12/94
02531     Purpose:    Simple CaretNode constructor, it is required so that SimpleCopy will work.
02532 ********************************************************************************************/
02533 
02534 CaretNode::CaretNode(): VisibleTextNode() // Call the base class
02535 {
02536 }
02537  
02538 
02539 /********************************************************************************************
02540 >   CaretNode::CaretNode(Node* ContextNode, AttachNodeDirection Direction)
02541 
02542     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
02543     Created:    07/02/95
02544     Inputs:     ContextNode: Pointer to a node which this node is to be attached to.     
02545         
02546                 Direction: 
02547             
02548                 Specifies the direction in which the node is to be attached to the 
02549                 ContextNode. The values this variable can take are as follows: 
02550                                   
02551                 PREV      : Attach node as a previous sibling of the context node
02552                 NEXT      : Attach node as a next sibling of the context node
02553                 FIRSTCHILD: Attach node as the first child of the context node
02554                 LASTCHILD : Attach node as a last child of the context node  
02555                 
02556     Purpose:    The main CaretNode constructor
02557 ********************************************************************************************/
02558 
02559 CaretNode::CaretNode(Node* ContextNode,  
02560                         AttachNodeDirection Direction): VisibleTextNode(ContextNode, Direction)
02561 {
02562 }
02563 
02564 /********************************************************************************************
02565 >   Node* CaretNode::SimpleCopy()
02566 
02567     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
02568     Created:    21/12/94
02569     Returns:    NULL (See below)
02570     Purpose:    It is illegal to copy a CaretNode, therefore this function will generate an error
02571                 if called.  
02572                 But blends, moulds etc. call this function so I (Peter) have implemented it
02573                 Fix after the show
02574 ********************************************************************************************/
02575 
02576 Node* CaretNode::SimpleCopy()
02577 {
02578     // Make a new CaretNode and then copy things into it
02579     CaretNode* NodeCopy = new CaretNode();
02580 
02581     ERROR1IF(NodeCopy == NULL, NULL, _R(IDE_NOMORE_MEMORY)); 
02582 
02583     if (NodeCopy != NULL)
02584         CopyNodeContents(NodeCopy);
02585     
02586     return NodeCopy;
02587 }
02588 
02589 
02590 /********************************************************************************************
02591 >   UINT32 CaretNode::GetNodeSize() const 
02592 
02593     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
02594     Created:    21/12/94
02595     Returns:    The size of the node in bytes
02596     Purpose:    For finding the size of the CaretNode. 
02597 ********************************************************************************************/
02598 
02599 UINT32 CaretNode::GetNodeSize() const 
02600 {
02601     return (sizeof(CaretNode)); 
02602 }
02603 
02604 
02605 /********************************************************************************************
02606 >   void CaretNode::GetDebugDetails(StringBase* Str) 
02607 
02608     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
02609     Created:    1/2/95
02610     Outputs:    Str: String giving debug info about the node
02611     Purpose:    For obtaining debug information about the Node. 
02612                 This fn can be deleted before we ship 
02613 ********************************************************************************************/
02614 
02615 void CaretNode::GetDebugDetails(StringBase* Str)
02616 {
02617 #if DEBUG_TREE
02618     VisibleTextNode::GetDebugDetails(Str);
02619 #endif
02620 }
02621 
02622 
02623 /********************************************************************************************
02624 >   Path* CaretNode::CreatePath(Matrix* pMatrix)
02625 
02626     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
02627     Created:    21/395
02628     Inputs:     pMatrix - transform to be applied to the caret
02629     Returns:    pointer to new path (or NULL if fails)
02630     Purpose:    Create a caret path
02631 ********************************************************************************************/
02632                                 
02633 Path* CaretNode::CreatePath(Matrix* pMatrix)
02634 {   
02635     ERROR2IF(pMatrix==NULL,NULL,"CaretNode::CreatePath() - pMatrix==NULL");
02636 
02637     TextLine* pTextLine=(TextLine*)FindParent();
02638     ERROR2IF(pTextLine==NULL,FALSE,"CaretNode::CreatePath() - pTextLine==NULL");
02639 
02640     // find italic status on caret
02641     NodeAttribute* pAttr;
02642     BOOL Italic=FALSE;
02643     if (FindAppliedAttribute(CC_RUNTIME_CLASS(AttrTxtItalic), &pAttr))
02644         Italic=((TxtItalicAttribute*)(pAttr->GetAttributeValue()))->ItalicOn;
02645 
02646     // find script offest
02647     FIXED16 ScriptOffset=0;
02648     if (FindAppliedAttribute(CC_RUNTIME_CLASS(AttrTxtScript), &pAttr))
02649         ScriptOffset=((TxtScriptAttribute*)(pAttr->GetAttributeValue()))->Offset;
02650 
02651     // find caret height
02652     MILLIPOINT LineSize  = pTextLine->GetLineSize();
02653     MILLIPOINT CaretSize = LineSize;
02654     if (FindAppliedAttribute(CC_RUNTIME_CLASS(AttrTxtFontSize), &pAttr))
02655         CaretSize=((TxtFontSizeAttribute*)(pAttr->GetAttributeValue()))->FontSize;
02656 
02657     // find baseline shift
02658 //  MILLIPOINT BaseLineShift=0;
02659 //  if (FindAppliedAttribute(CC_RUNTIME_CLASS(AttrTxtBaseLine), &pAttr))
02660 //      BaseLineShift=((TxtBaseLineAttribute*)(pAttr->GetAttributeValue()))->Value;
02661 
02662     // calc caret top and bottom points accounting for italic and baseline shift
02663     FIXED16             CaretRatio=(LineSize!=0) ? Div32By32(CaretSize,LineSize) : 1;
02664     DocCoord            CaretTop(0, XLONG(pTextLine->GetLineDescent()) * CaretRatio );
02665     DocCoord            CaretBot(0, XLONG(pTextLine->GetLineAscent()) * CaretRatio );
02666     if (Italic && ScriptOffset==0)
02667     {
02668         const double SlantRatio = tan(15.0*PI/180);
02669         CaretTop.x = (INT32) ((double)CaretTop.y * SlantRatio);
02670         CaretBot.x = (INT32) ((double)CaretBot.y * SlantRatio);
02671     }
02672 
02673     // get caret path
02674     Path* pCaretPath=new Path(); 
02675     BOOL ok=(pCaretPath!=NULL);
02676     if (ok) ok=pCaretPath->Initialise(2,12);
02677     if (ok) ok=pCaretPath->AddMoveTo(CaretTop);
02678     if (ok) ok=pCaretPath->AddLineTo(CaretBot);
02679 
02680     // apply transform to caret path
02681     DocCoord* pPathCoords=NULL;
02682     if (ok) pPathCoords=pCaretPath->GetCoordArray();                                 
02683     if (ok) ok=(pPathCoords!=NULL);
02684     if (ok) pMatrix->transform((Coord*)pPathCoords, pCaretPath->GetNumCoords());
02685 
02686     // if not OK, delete caret path and set return path pointer to NULL
02687     if (!ok)
02688     {
02689         delete pCaretPath;
02690         pCaretPath=NULL;
02691     }
02692 
02693     return pCaretPath;
02694 } 
02695 
02696 
02697 /********************************************************************************************
02698 >   void CaretNode::RenderObjectBlobs(RenderRegion* pRenderRegion)
02699 
02700     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
02701     Created:    14/2/95
02702     Inputs:     pRender - The region to render into
02703     Returns:    FALSE if fails
02704     Purpose:    Renders the caret's path into the pRender render region
02705 ********************************************************************************************/
02706 
02707 void CaretNode::RenderObjectBlobs(RenderRegion* pRenderRegion)
02708 {
02709     if (RenderObjectBlobsCore(pRenderRegion)==FALSE)
02710         InformError();
02711 }
02712 
02713 
02714 /********************************************************************************************
02715 >   BOOL CaretNode::RenderObjectBlobsCore(RenderRegion* pRenderRegion)
02716 
02717     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
02718     Created:    14/2/95
02719     Inputs:     pRender: The region to render into
02720     Returns:    FALSE if fails
02721     Purpose:    Renders the caret's path into the pRender render region
02722 ********************************************************************************************/
02723 
02724 BOOL CaretNode::RenderObjectBlobsCore(RenderRegion* pRenderRegion)
02725 {
02726 #if !defined(EXCLUDE_FROM_RALPH)
02727     ERROR2IF(pRenderRegion==NULL,FALSE,"CaretNode::RenderObjectBlobsCore() - pRenderRegion==NULL");
02728 
02729     TextStory* pTextStory = this->FindParentStory();
02730     ERROR2IF(pTextStory==NULL,FALSE,"CaretNode::RenderObjectBlobsCore() - pTextStory==NULL");
02731 
02732     // get the caret path transformed to the correct place in the doc
02733     Matrix matrix;
02734     if (GetStoryAndCharMatrix(&matrix)==FALSE)
02735         return FALSE;
02736     Path* pCaretPath=CreatePath(&matrix);
02737     BOOL ok=(pCaretPath!=NULL);
02738 
02739     // draw the caret path in red (line width?)
02740     if (ok)
02741     {
02742         pRenderRegion->SaveContext();
02743         pRenderRegion->SetLineColour(RED);
02744         pRenderRegion->DrawPath(pCaretPath);
02745         pRenderRegion->RestoreContext();
02746     }
02747 
02748     // delete the caret path
02749     delete pCaretPath;
02750 
02751     return ok;
02752 #else
02753     return TRUE;
02754 #endif
02755 }
02756 
02757 
02758 /*******************************************************************************************
02759 >   virtual BOOL CaretNode::ExportRender(RenderRegion* pRegion)
02760 
02761     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
02762     Created:    14/4/95
02763     Inputs:     pRegion - points to the export render region
02764     Returns:    TRUE if rendered OK (FALSE=>use normal rendering)
02765     Purpose:    This function is called when the render function passes through this node
02766                 It outputs the  Text Object start and end tokens
02767 ********************************************************************************************/
02768 
02769 BOOL CaretNode::ExportRender(RenderRegion* pRegion)
02770 {
02771 #if EXPORT_TEXT
02772 // BODGE TEXT - need to export caret in a comment!
02773     if (pRegion->IsKindOf(CC_RUNTIME_CLASS(EPSRenderRegion)))
02774     {
02775         /*EPSExportDC *pDC=*/(EPSExportDC*)pRegion->GetRenderDC();
02776 //      pDC->OutputToken("ctk");
02777 //      pDC->OutputNewLine();
02778         return TRUE;
02779     }
02780 #endif
02781     return FALSE;
02782 }
02783 
02784 
02785 /********************************************************************************************
02786 >   virtual void CaretNode::Describe(BOOL Plural, BOOL Verbose = TRUE) 
02787 
02788     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
02789     Created:    15/03/95
02790     Inputs:     Plural - FALSE to describe a single caret
02791                          TRUE to describe many
02792     Returns:    String describing what the node is
02793     Purpose:    For obtaining a desciption about the node to use in the status line
02794 ********************************************************************************************/
02795 
02796 String CaretNode::Describe(BOOL Plural, BOOL Verbose)
02797 {
02798     if (Plural)
02799         return(String(_R(IDS_CARETSDESCRIPTION)));  
02800     else
02801         return(String(_R(IDS_CARETDESCRIPTION))); 
02802 }
02803 
02804 
02805 /********************************************************************************************
02806 >   virtual DocRect CaretNode::GetBlobBoundingRect()
02807 
02808     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
02809     Created:    21/3/95
02810     Returns:    the caret's bounds
02811     Purpose:    get the caret's blob bounds
02812     Note:       Abuse of bounding box cache should really be for renderable bounds
02813                 but the caret has none!
02814 ********************************************************************************************/
02815 
02816 DocRect CaretNode::GetBlobBoundingRect()
02817 {
02818     if (IsBoundingRectValid==FALSE)
02819         if (ValidateBoundingRect()==FALSE)
02820             InformError();
02821 
02822     return BlobBounds;
02823 }
02824 
02825 
02826 /********************************************************************************************
02827 >   virtual DocRect CaretNode::GetBoundingRect(BOOL DontUseAttr=FALSE, BOOL HitTest=FALSE)
02828 
02829     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
02830     Created:    21/3/95
02831     Inputs:     DontUseAttr - not used
02832                 HitTest     - not used
02833     Returns:    the caret's renderable bounds
02834 ********************************************************************************************/
02835 
02836 DocRect CaretNode::GetBoundingRect(BOOL DontUseAttr, BOOL HitTest)
02837 {
02838     if (IsBoundingRectValid==FALSE)
02839         if (ValidateBoundingRect()==FALSE)
02840             InformError();
02841 
02842     return BoundingRectangle;
02843 }
02844 
02845 
02846 /********************************************************************************************
02847 >   BOOL CaretNode::ValidateBoundingRect(FormatRegion* pFormatRegion=NULL)
02848 
02849     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
02850     Created:    21/3/95
02851     Inputs:     pFormatRegion - not used
02852     Returns:    FALSE if fails
02853     Purpose:    recache the caret's renderable and blob bounding rects
02854 ********************************************************************************************/
02855 
02856 BOOL CaretNode::ValidateBoundingRect(FormatRegion* pFormatRegion)
02857 {
02858 #if !defined(EXCLUDE_FROM_RALPH)
02859     BOOL ok=TRUE;
02860 
02861     // get the overall matrix to apply to the caret
02862     Matrix matrix;
02863     if (GetStoryAndCharMatrix(&matrix)==FALSE)
02864         return FALSE;
02865 
02866     // get a zero size rect at the correct position in the doc
02867     // for the renderable bounds of the caret (uses by ScrollToShow)
02868     DocCoord temp(0,0);
02869     matrix.transform((Coord*)&temp,1);
02870     DocRect RendRect(temp,temp);
02871 
02872     // get the bounds of the caret path for the blob bounds
02873     Path* pCaretPath=CreatePath(&matrix);
02874     DocRect BlobRect(0,0,0,0);
02875     ok=(pCaretPath!=NULL);
02876     if (ok)
02877     {
02878         DocCoord* pCoords=pCaretPath->GetCoordArray();
02879         PathVerb* pVerbs=pCaretPath->GetVerbArray();
02880         ok=(pVerbs!=NULL && pCoords!=NULL);
02881         if (ok)
02882         {
02883             GDrawContext *GD = GRenderRegion::GetStaticDrawContext();
02884 
02885             if (GD != NULL)
02886             {
02887                 ok=!(GD->CalcStrokeBBox((POINT*)pCoords, pVerbs, pCaretPath->GetNumCoords(),
02888                                      (LPRECT)(&BlobRect), 0, 2, CAPS_ROUND, JOIN_ROUND, NULL));
02889             }
02890 
02891             if (!ok) ERROR2RAW("CaretNode::ValidateBoundingRect() - GDraw_CalcStrokeBBox() failed");
02892         }
02893         delete pCaretPath;
02894     }
02895 
02896     // Inflate the blob bounds, so that the Caret is at least a pixel wide
02897     if (View::GetCurrent() != NULL)
02898     {
02899         INT32 PixWidth = (View::GetCurrent()->GetScaledPixelWidth()).MakeLong();
02900         BlobRect.Inflate(PixWidth/2);
02901     }
02902 
02903     // update the cached values
02904     BoundingRectangle   = RendRect;
02905     BlobBounds          = BlobRect;
02906     IsBoundingRectValid = TRUE;
02907     return ok;
02908 #else
02909     return TRUE;
02910 #endif
02911 }
02912 
02913 
02914 /********************************************************************************************
02915 >   BOOL CaretNode::HasMoved();
02916 
02917     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
02918     Created:    17/3/95
02919     Returns:    FALSE if fails
02920     Purpose:    reposition the caret after it has moved
02921                 If possible to the right of the previous char as the caret takes its attributes
02922                 from this char so the caret's position reflects it's baseline shift correctly
02923 ********************************************************************************************/
02924 
02925 BOOL CaretNode::HasMoved()
02926 {
02927 #if !defined(EXCLUDE_FROM_RALPH)
02928     AbstractTextChar* pPrevATC=(AbstractTextChar*)(this->FindPrevious(CC_RUNTIME_CLASS(AbstractTextChar)));
02929     BOOL AfterPrevChar = (pPrevATC!=NULL);
02930 
02931     // if positioning the caret after the previous char and its a kern code
02932     // and its on a path and a silly size, position the caret before the next char
02933     if (AfterPrevChar && IS_A(pPrevATC,KernCode))
02934     {
02935         TextStory* pTextStory = this->FindParentStory();
02936         ERROR2IF(pTextStory==NULL,FALSE,"CaretNode::HasMoved() - could not find caret's parent story!");
02937         if ( pTextStory->GetTextPath()!=NULL && ((KernCode*)pPrevATC)->GetValue().x>1000 )
02938             AfterPrevChar = FALSE;
02939     }
02940 
02941     // if positioning caret after last char, use prev char's info plus advance
02942     // else just use next char's info
02943     Matrix matrix;
02944     MILLIPOINT pos=0;
02945     if (AfterPrevChar)
02946     {
02947         const MILLIPOINT advance=pPrevATC->GetVisibleAdvance();
02948         matrix  = Matrix(advance,0);
02949         matrix *= pPrevATC->GetMatrix();
02950         pos     = pPrevATC->GetPosInLine()+advance;
02951     }
02952     else
02953     {
02954         AbstractTextChar* pNextATC=(AbstractTextChar*)(this->FindNext(CC_RUNTIME_CLASS(AbstractTextChar)));
02955         ERROR2IF(pNextATC==NULL,FALSE,"CaretNode::HasMoved() - no AbstractTextChar before or after caret!");
02956         matrix = pNextATC->GetMatrix();
02957         pos    = pNextATC->GetPosInLine();
02958     }
02959 
02960     SetMatrix(matrix);
02961     SetPosInLine(pos);
02962     InvalidateBoundingRect();
02963 #endif
02964     return TRUE;
02965 }
02966 
02967 
02968 /********************************************************************************************
02969 >   virtual BOOL CaretNode::DiscardsAttributeChildren()
02970 
02971     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
02972     Created:    4/5/95
02973     Returns:    TRUE
02974     Purpose:    When attributes are applied to the caret, we cannot generate undo info
02975                 as children of the CaretNode are thrown away in a non-undoable way.
02976 
02977     Notes:      Phil, 24/09/2005
02978                 The usage of this function has changed subtly today. It used to prevent
02979                 both attribute optimisation and undo recording on Caret nodes.
02980                 As of today it just prevents undo recording - attribute optimisation
02981                 goes ahead like normal on Caret nodes so that they behave more consistently.
02982 
02983 ********************************************************************************************/
02984 
02985 BOOL CaretNode::DiscardsAttributeChildren() const
02986 {
02987     return TRUE;
02988 }
02989 
02990 
02991 /********************************************************************************************
02992 >   BOOL CaretNode::DoApplyAttrsTo(UndoableOperation* pUndoOp, VisibleTextNode* pDstVTN, BOOL bDeleteDups)
02993 
02994     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
02995     Created:    9/7/96
02996     Inputs:     pDstVTN - VisibleTextNode to apply caret attrs to
02997     Returns:    FALSE if fails
02998     Purpose:    Apply attrs on caret to given VTN (on same line) ensuring tree left optimal
02999 ********************************************************************************************/
03000 
03001 BOOL CaretNode::DoApplyAttrsTo(UndoableOperation* pUndoOp, VisibleTextNode* pDstVTN, BOOL bDeleteDups)
03002 {
03003     ERROR2IF(pUndoOp==NULL,FALSE,"CaretNode::DoApplyAttrsTo() - pUndoOp==NULL");
03004     ERROR2IF(pDstVTN==NULL,FALSE,"CaretNode::DoApplyAttrsTo() - pDstVTN==NULL");
03005 
03006     TextLine* pCaretLine = this->FindParentLine();
03007     ERROR2IF(pCaretLine==NULL,FALSE,"CaretNode::DoApplyAttrsTo() - caret has no TextLine parent");
03008     TextLine* pDstVTNLine = pDstVTN->FindParentLine();
03009     ERROR2IF(pDstVTNLine==NULL,FALSE,"CaretNode::DoApplyAttrsTo() - dest VTN has no TextLine parent");
03010 if (bDeleteDups)
03011 {
03012     ERROR2IF(pDstVTNLine!=pCaretLine,FALSE,"CaretNode::DoApplyAttrsTo() - caret and pDstVTN not on same line");
03013 }
03014 
03015     // determine if attr types on caret are already localised
03016     AbstractTextChar* pATC = (AbstractTextChar*)(pCaretLine->FindFirstChild(CC_RUNTIME_CLASS(AbstractTextChar)));
03017     ERROR2IF(pATC==NULL,FALSE,"OpTextFormat::DoInsertCharHelper() - caret line has no AbstaractTextChars");
03018     BOOL CommonAttrsAffected = !pATC->HasAttrTypesOn(this);
03019 
03020     // if attr types on the caret are not localised, localise them
03021     AttrTypeSet CaretsAttrTypes;
03022     this->AddChildAttrTypesToSet(&CaretsAttrTypes);
03023     if (CommonAttrsAffected)
03024         if (!pUndoOp->DoLocaliseForAttrChange(pDstVTN,&CaretsAttrTypes,NULL))
03025             return FALSE;
03026 
03027 // BODGE WORDWRAP - causes dup attrs if applying defalut attr on caret to new char in line of non-default
03028 
03029     // now copy carets attrs to new char, deleting any duplicates
03030     NodeAttribute* pCaretAttr = (NodeAttribute*)(this->FindFirstChild(CC_RUNTIME_CLASS(NodeAttribute)));
03031     while (pCaretAttr!=NULL)
03032     {
03033         NodeAttribute* pDupAttr = pDstVTN->GetChildAttrOfType(pCaretAttr->GetAttributeType());
03034 
03035         // If we have found a duplicate and we are allowed to delete it, do so
03036         if (pDupAttr!=NULL && bDeleteDups)
03037         {
03038             pDupAttr->CascadeDelete();
03039             delete pDupAttr;
03040         }
03041 
03042         // If we didn't find a duplicate or we did and we deleted it then
03043         // copy the caret's attribute
03044         if (pDupAttr==NULL || bDeleteDups)
03045         {
03046             Node* pAttrCopy; 
03047             if (!pCaretAttr->NodeCopy(&pAttrCopy))
03048                 return FALSE;
03049             pAttrCopy->AttachNode(pDstVTN, LASTCHILD);
03050         }
03051 
03052         pCaretAttr = (NodeAttribute*)(pCaretAttr->FindNext(CC_RUNTIME_CLASS(NodeAttribute)));
03053     }
03054 
03055     // if attr types on caret were localised, factor them out
03056     if (CommonAttrsAffected)
03057         if (!pUndoOp->DoFactorOutAfterAttrChange(pDstVTN, &CaretsAttrTypes))
03058             return FALSE;
03059 
03060     return TRUE;
03061 }
03062 
03063 
03064 /********************************************************************************************
03065 >   virtual void CaretNode::SetSelected(BOOL Status)
03066 
03067     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03068     Created:    11/5/95
03069     Inputs:     Status - TRUE to select the caret
03070                          FALSE to deselect it
03071     Purpose:    Overides the normal SetSelected call so we can ensure that the caret is not
03072                 selected outside the TextTool.
03073 ********************************************************************************************/
03074 
03075 void CaretNode::SetSelected(BOOL Status)
03076 {
03077 #if !defined(EXCLUDE_FROM_RALPH)
03078     if (!TextTool::IsCurrentTool())
03079     {
03080         TextStory* pStory = this->FindParentStory();
03081         if (pStory != NULL)
03082             pStory->SetSelected(Status);
03083     }
03084     else
03085         BaseTextClass::SetSelected(Status);
03086 #endif
03087 }
03088 
03089 
03090 /********************************************************************************************
03091 >   BOOL CaretNode::WritePreChildrenWeb(BaseCamelotFilter *pFilter)
03092     BOOL CaretNode::WritePreChildrenNative(BaseCamelotFilter *pFilter)
03093 
03094     Author:     Andy_Hayward (Xara Group Ltd) <camelotdev@xara.com>
03095     Created:    10/07/96
03096     Inputs:     pFilter - new file format filter to write record to
03097     Returns:    TRUE if successful, FALSE otherwise
03098     Purpose:    Writes a caret node record to the new file format filter
03099 ********************************************************************************************/
03100 
03101 BOOL CaretNode::WritePreChildrenWeb(BaseCamelotFilter *pFilter)
03102 {
03103 //#ifdef DO_EXPORT
03104 //  return CXaraFileTxtCaret::WritePreChildrenWeb(pFilter, this);
03105 //#else
03106     return FALSE;
03107 //#endif
03108 }
03109 
03110 BOOL CaretNode::WritePreChildrenNative(BaseCamelotFilter *pFilter)
03111 {
03112 //#ifdef DO_EXPORT
03113 //  return CXaraFileTxtCaret::WritePreChildrenNative(pFilter, this);
03114 //#else
03115     return FALSE;
03116 //#endif
03117 }
03118 
03119 BOOL CaretNode::CanWriteChildrenWeb(BaseCamelotFilter* pFilter)
03120 {
03121     return FALSE;
03122 }
03123 
03124 BOOL CaretNode::CanWriteChildrenNative(BaseCamelotFilter* pFilter)
03125 {
03126     return FALSE;
03127 }
03128 
03130 // EOLNode methods
03131 
03132 /********************************************************************************************
03133 >   EOLNode::EOLNode()
03134 
03135     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
03136     Created:    21/12/94
03137     Purpose:    Simple EOLNode constructor, it is required so that SimpleCopy will work.
03138 ********************************************************************************************/
03139 
03140 EOLNode::EOLNode(): AbstractTextChar() // Call the base class
03141 {
03142     Virtual   = FALSE;
03143 }
03144 
03145  
03146 /********************************************************************************************
03147 >   EOLNode::EOLNode(Node* ContextNode, AttachNodeDirection Direction)
03148 
03149     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
03150     Created:    07/02/95
03151     Inputs:     ContextNode: Pointer to a node which this node is to be attached to.     
03152         
03153                 Direction: 
03154             
03155                 Specifies the direction in which the node is to be attached to the 
03156                 ContextNode. The values this variable can take are as follows: 
03157                                   
03158                 PREV      : Attach node as a previous sibling of the context node
03159                 NEXT      : Attach node as a next sibling of the context node
03160                 FIRSTCHILD: Attach node as the first child of the context node
03161                 LASTCHILD : Attach node as a last child of the context node  
03162                 
03163     Purpose:    The main EOLNode constructor
03164 ********************************************************************************************/
03165 
03166 EOLNode::EOLNode(Node* ContextNode,  
03167                     AttachNodeDirection Direction): AbstractTextChar(ContextNode, Direction)
03168 {
03169     Virtual   = FALSE;
03170 }
03171 
03172 
03173 /********************************************************************************************
03174 >   Node* EOLNode::SimpleCopy()
03175 
03176     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
03177     Created:    21/12/94
03178     Returns:    A copy of the node, or NULL if we are out of memory 
03179     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
03180                 The function is virtual, and must be defined for all derived classes of Node  
03181     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of memory
03182                 error and the function returns NULL. 
03183 ********************************************************************************************/
03184 
03185 Node* EOLNode::SimpleCopy()
03186 {
03187     // Make a new TextChar and then copy things into it
03188     EOLNode* NodeCopy = new EOLNode();
03189 
03190     if (NodeCopy)
03191         CopyNodeContents(NodeCopy);
03192     
03193     return NodeCopy;
03194 
03195 }
03196 
03197 
03198 /********************************************************************************************
03199 >   virtual void EOLNode::Describe(BOOL Plural, BOOL Verbose = TRUE) 
03200 
03201     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03202     Created:    15/03/95
03203     Inputs:     Plural - FALSE to describe a single EOLNode
03204                          TRUE to describe many
03205     Returns:    String describing what the node is
03206     Purpose:    For obtaining a desciption about the node to use in the status line
03207 ********************************************************************************************/
03208 
03209 String EOLNode::Describe(BOOL Plural, BOOL Verbose)
03210 {
03211     if (Plural)
03212         return(String(_R(IDS_EOLNODES)));  
03213     else
03214         return(String(_R(IDS_EOLNODE))); 
03215 }
03216 
03217 
03218 /***********************************************************************************************
03219 >   void EOLNode::CopyNodeContents(EOLNode* NodeCopy)
03220 
03221     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
03222     Created:    28/4/93
03223     Inputs:           
03224     Outputs:    A copy of this node
03225     Purpose:    This method copies the node's contents to the node pointed to by NodeCopy.
03226     Errors:     An assertion failure will occur if NodeCopy is NULL
03227 ***********************************************************************************************/
03228 
03229 void EOLNode::CopyNodeContents(EOLNode* NodeCopy)
03230 {
03231     // Ask the base class to do its bit
03232     AbstractTextChar::CopyNodeContents( NodeCopy );
03233 
03234     // Copy the rest of the data in here
03235     NodeCopy->Virtual   = Virtual;
03236 }
03237 
03238 
03239 /***********************************************************************************************
03240 >   void EOLNode::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
03241 
03242     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03243     Created:    18/12/2003
03244     Outputs:    -
03245     Purpose:    Polymorphically copies the contents of this node to another
03246     Errors:     An assertion failure will occur if NodeCopy is NULL
03247     Scope:      protected
03248                                      
03249 ***********************************************************************************************/
03250 
03251 void EOLNode::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
03252 {
03253     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
03254     ENSURE(IS_A(pNodeCopy, EOLNode), "PolyCopyNodeContents given wrong dest node type");
03255 
03256     if (IS_A(pNodeCopy, EOLNode))
03257         CopyNodeContents((EOLNode*)pNodeCopy);
03258 }
03259 
03260 
03261 
03262 /********************************************************************************************
03263 >   UINT32 EOLNode::GetNodeSize() const 
03264 
03265     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
03266     Created:    21/12/94
03267     Returns:    The size of the node in bytes
03268     Purpose:    For finding the size of the node 
03269 ********************************************************************************************/
03270 
03271 UINT32 EOLNode::GetNodeSize() const 
03272 {
03273     return (sizeof(EOLNode)); 
03274 }
03275 
03276 
03277 /********************************************************************************************
03278 >   void EOLNode::GetDebugDetails(StringBase* Str) 
03279 
03280     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
03281     Created:    1/2/95
03282     Outputs:    Str: String giving debug info about the node
03283     Purpose:    For obtaining debug information about the Node. 
03284                 This fn can be deleted before we ship 
03285 ********************************************************************************************/
03286 
03287 void EOLNode::GetDebugDetails(StringBase* pStr)
03288 {
03289 #if DEBUG_TREE
03290     AbstractTextChar::GetDebugDetails(pStr);
03291 
03292     String_256 TempStr;
03293 
03294     switch (IsVirtual())
03295     {
03296         case TRUE:  TempStr._MakeMsg(TEXT("\r\nIs virtual"));  break;
03297         case FALSE: TempStr._MakeMsg(TEXT("\r\nIs physical")); break;
03298     }
03299     *pStr += TempStr;
03300 #endif
03301 }
03302 
03303     
03304 /********************************************************************************************
03305 >   virtual DocRect EOLNode::GetBoundingRect(BOOL DontUseAttr=FALSE, BOOL HitTest=FALSE)
03306 
03307     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
03308     Created:    21/3/95
03309     Inputs:     DontUseAttr - not used (EOL is not rendered)
03310                 HitTest     - TRUE if being called during HitTest
03311     Returns:    the EOL bounds (zero size but in correct position
03312     Purpose:    Get the EOL's bounds
03313                 If the cached bounds are invalid, recalculate them
03314 ********************************************************************************************/
03315 
03316 DocRect EOLNode::GetBoundingRect(BOOL DontUseAttr, BOOL HitTest)
03317 {
03318     if (IsBoundingRectValid==FALSE)
03319         if (ValidateBoundingRect()==FALSE)
03320             InformError();
03321 
03322     return BoundingRectangle;
03323 }
03324 
03325 
03326 /********************************************************************************************
03327 >   BOOL EOLNode::ValidateBoundingRect(FormatRegion* pFormatRegion=NULL)
03328 
03329     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
03330     Created:    21/3/95
03331     Inputs:     pFormatRegion - not used
03332     Returns:    FALSE if fails
03333     Purpose:    calculate the EOL bounds in the document
03334 ********************************************************************************************/
03335 
03336 BOOL EOLNode::ValidateBoundingRect(FormatRegion* pFormatRegion)
03337 {
03338     Matrix matrix;
03339     if (GetStoryAndCharMatrix(&matrix)==FALSE)
03340         return FALSE;
03341 
03342     // get a zero size rect at correct place in the doc for the renderable bounds of the EOL
03343     DocCoord temp(0,0);
03344     matrix.transform(&temp);
03345     BoundingRectangle   = DocRect(temp,temp);
03346     IsBoundingRectValid = TRUE;
03347     return TRUE;
03348 }
03349 
03350 
03351 /********************************************************************************************
03352 >   virtual DocRect EOLNode::GetBlobBoundingRect()
03353 
03354     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03355     Created:    11/5/95
03356     Returns:    the EOLNode's blob bounds
03357     Purpose:    get the EOLNode's blob bounds
03358 ********************************************************************************************/
03359 
03360 DocRect EOLNode::GetBlobBoundingRect()
03361 {
03362     Path RenderPath;
03363     DocRect Bounds(0,0,1,1);
03364     if (GetBlobPath(&RenderPath))
03365         Bounds = RenderPath.GetBoundingRect();
03366 
03367     return Bounds;
03368 }
03369 
03370 
03371 /********************************************************************************************
03372 >   void EOLNode::RenderObjectBlobs(RenderRegion* pRenderRegion)
03373 
03374     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03375     Created:    11/5/95
03376     Inputs:     pRenderRegion - region to render the blobs into
03377     Purpose:    Renders the selection blobs for an EOLNode
03378 ********************************************************************************************/
03379 
03380 void EOLNode::RenderObjectBlobs(RenderRegion* pRenderRegion)
03381 {
03382 #if !defined(EXCLUDE_FROM_RALPH)
03383     Path RenderPath;
03384     if (GetBlobPath(&RenderPath))
03385     {
03386         DocColour Trans(COLOUR_TRANS);
03387         pRenderRegion->SetLineWidth(0);
03388         pRenderRegion->SetLineColour(Trans);
03389         pRenderRegion->SetFillColour(COLOUR_UNSELECTEDBLOB);
03390         pRenderRegion->DrawPath(&RenderPath);
03391     }
03392     else
03393         InformError();
03394 #endif
03395 }
03396 
03397 
03398 /********************************************************************************************
03399 >   void EOLNode::RenderTinyBlobs(RenderRegion* pRenderRegion)
03400 
03401     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03402     Created:    11/5/95
03403     Inputs:     pRenderRegion - region to render the blobs into
03404     Purpose:    Renders the selection blobs for an EOLNode
03405 ********************************************************************************************/
03406 
03407 void EOLNode::RenderTinyBlobs(RenderRegion* pRenderRegion)
03408 {
03409 #if !defined(EXCLUDE_FROM_RALPH)
03410     RenderObjectBlobs(pRenderRegion);
03411 #endif
03412 }
03413 
03414 
03415 /********************************************************************************************
03416 >   BOOL EOLNode::GetBlobPath(Path*)
03417 
03418     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
03419     Created:    11/5/95
03420     Inputs:     Pointer to a path
03421     Returns:    TRUE/FALSE for success/failure
03422     Purpose:    Builds a path for rendering the blobs for an EOLNode
03423 ********************************************************************************************/
03424 
03425 BOOL EOLNode::GetBlobPath(Path* pPath)
03426 {
03427 #if !defined(EXCLUDE_FROM_RALPH)
03428     ERROR2IF(pPath==NULL, FALSE, "Path pointer was NULL");
03429     TextLine* pParentLine = this->FindParentLine();
03430     ERROR2IF(pParentLine==NULL, FALSE, "EOLNode didn't have a parent TextLine");
03431     const MILLIPOINT LineAscent = pParentLine->GetLineAscent();
03432     const MILLIPOINT HalfLA     = LineAscent/2;
03433     const MILLIPOINT QuarterLA  = LineAscent/4;
03434     BOOL ok = TRUE;
03435     if (ok) ok = pPath->Initialise(4,1);
03436     if (ok) ok = pPath->AddMoveTo(DocCoord(QuarterLA,0));
03437     if (ok) ok = pPath->AddLineTo(DocCoord(QuarterLA, HalfLA));
03438     if (ok) ok = pPath->AddLineTo(DocCoord(HalfLA+QuarterLA, QuarterLA));
03439     if (ok) ok = pPath->AddLineTo(DocCoord(QuarterLA,0));
03440     if (ok)
03441     {
03442         ok = pPath->CloseSubPath();
03443         pPath->IsFilled = TRUE;
03444     }
03445 
03446     // Transform the path
03447     if (ok)
03448     {
03449         Matrix matrix;
03450         if (ok) ok = GetStoryAndCharMatrix(&matrix);
03451         if (ok) matrix.transform((Coord*)(pPath->GetCoordArray()), pPath->GetNumCoords());
03452     }
03453 
03454     return ok;
03455 #else
03456     return FALSE;
03457 #endif
03458 }
03459 /********************************************************************************************
03460 
03461 >   BOOL EOLNode::WritePreChildrenWeb(BaseCamelotFilter *pFilter)
03462     BOOL EOLNode::WritePreChildrenNative(BaseCamelotFilter *pFilter)
03463 
03464     Author:     Andy_Hayward (Xara Group Ltd) <camelotdev@xara.com>
03465     Created:    10/07/96
03466     Inputs:     pFilter - new file format filter to write record to
03467     Returns:    TRUE if successful, FALSE otherwise
03468     Purpose:    Writes an end of line record to the new file format filter
03469 
03470 ********************************************************************************************/
03471 
03472 BOOL EOLNode::WritePreChildrenWeb(BaseCamelotFilter *pFilter)
03473 {
03474 #ifdef DO_EXPORT
03475     return CXaraFileTxtEOL::WritePreChildrenWeb(pFilter, this);
03476 #else
03477     return FALSE;
03478 #endif
03479 }
03480 
03481 BOOL EOLNode::WritePreChildrenNative(BaseCamelotFilter *pFilter)
03482 {
03483 #ifdef DO_EXPORT
03484     return CXaraFileTxtEOL::WritePreChildrenNative(pFilter, this);
03485 #else
03486     return FALSE;
03487 #endif
03488 }
03489 
03490 /********************************************************************************************
03491 
03492 >   BOOL EOLNode::CanWriteChildrenWeb(BaseCamelotFilter *pFilter)
03493 
03494     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
03495     Created:    30/8/96
03496     Inputs:     pFilter - new file format filter to write record to
03497     Returns:    TRUE if successful, FALSE otherwise
03498     Purpose:    Asks if it's alright to write out the EOL's children
03499 
03500                 EOLs always say yes.  EOL nodes can't be female then.
03501 
03502 ********************************************************************************************/
03503 
03504 BOOL EOLNode::CanWriteChildrenWeb(BaseCamelotFilter *pFilter)
03505 {
03506     return TRUE;
03507 }
03508 
03509 //------------------------------------------------------------------------------
03510 // See EOLNode::CanWriteChildrenWeb(BaseCamelotFilter *pFilter) for more details
03511 
03512 BOOL EOLNode::CanWriteChildrenNative(BaseCamelotFilter *pFilter)
03513 {
03514     return TRUE;
03515 }
03516 
03517 /*******************************************************************************************
03518 >   virtual BOOL EOLNode::ExportRender(RenderRegion* pRegion)
03519 
03520     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
03521     Created:    14/4/95
03522     Inputs:     pRegion - points to the export render region
03523     Returns:    TRUE if rendered OK (FALSE=>use normal rendering)
03524     Purpose:    This function is called when the render function passes through this node
03525                 It outputs the Text Object start and end tokens
03526 ********************************************************************************************/
03527 
03528 BOOL EOLNode::ExportRender(RenderRegion* pRegion)
03529 {
03530 #if EXPORT_TEXT
03531 
03532     // (ChrisG - 3/11/00)
03533     if (pRegion->IsKindOf(CC_RUNTIME_CLASS(AIEPSRenderRegion)))
03534     {
03535         // if we were exporting the overflow data (i.e. we were exporting a path), then 
03536         //  finish off exporting this
03537         if (((AIEPSRenderRegion *) pRegion)->ExportingOnPath ())
03538             ((AIEPSRenderRegion *) pRegion)->OverflowTextFinish ();
03539     }
03540 
03541     return pRegion->WriteNewLine ();
03542 #else
03543     return FALSE;
03544 #endif
03545 }
03546 
03547 
03549 // KernCode methods
03550 
03551 /********************************************************************************************
03552 >   KernCode::KernCode()
03553 
03554     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
03555     Created:    21/12/94
03556     Purpose:    Simple KernCode constructor, it is required so that SimpleCopy will work.
03557                 You should not normally call this constructor as it does not initialise
03558                 the object.
03559 ********************************************************************************************/
03560 
03561 KernCode::KernCode(): AbstractTextChar()
03562 {
03563 }
03564 
03565 /********************************************************************************************
03566 >   KernCode::KernCode(DocCoord& KernValue)
03567 
03568     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
03569     Created:    21/12/94
03570     Inputs:     KernValue: Horizontal/Vertical kern value                  
03571     Purpose:    KernCode constructor
03572 ********************************************************************************************/
03573 
03574 KernCode::KernCode(DocCoord& KernValue): AbstractTextChar()
03575 {
03576     Value = KernValue;  
03577 }
03578 
03579  
03580 /********************************************************************************************
03581 >   KernCode::KernCode(Node* ContextNode, AttachNodeDirection Direction, DocCoord& KernValue)
03582 
03583     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
03584     Created:    21/12/94
03585     Inputs:     ContextNode: Pointer to a node which this node is to be attached to.     
03586         
03587                 Direction: 
03588             
03589                 Specifies the direction in which the node is to be attached to the 
03590                 ContextNode. The values this variable can take are as follows: 
03591                                   
03592                 PREV      : Attach node as a previous sibling of the context node
03593                 NEXT      : Attach node as a next sibling of the context node
03594                 FIRSTCHILD: Attach node as the first child of the context node
03595                 LASTCHILD : Attach node as a last child of the context node
03596                 
03597                 Value: Horizontal/Vertical kern value                  
03598 
03599     Purpose:    The main KernCode constructor
03600 ********************************************************************************************/
03601 
03602 KernCode::KernCode(Node* ContextNode, AttachNodeDirection Direction, 
03603                    DocCoord& KernValue): AbstractTextChar(ContextNode, Direction)
03604 {
03605     Value = KernValue;
03606 }
03607 
03608 
03609 /*******************************************************************************************
03610 >   virtual BOOL KernCode::ExportRender(RenderRegion* pRegion)
03611 
03612     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
03613     Created:    14/4/95
03614     Inputs:     pRegion - points to the export render region
03615     Returns:    TRUE if rendered OK (FALSE=>use normal rendering)
03616     Purpose:    This function is called when the render function passes through this node
03617                 It outputs the  Text Object start and end tokens
03618 ********************************************************************************************/
03619 
03620 BOOL KernCode::ExportRender(RenderRegion* pRegion)
03621 {
03622 #if EXPORT_TEXT
03623     if (pRegion->IsKindOf(CC_RUNTIME_CLASS(EPSRenderRegion)))
03624     {
03625         // Output any valid text attributes necessary
03626         ((EPSRenderRegion*)pRegion)->GetValidPathAttributes();
03627         ((EPSRenderRegion*)pRegion)->GetValidTextAttributes();
03628 
03629         EPSExportDC *pDC=(EPSExportDC*)pRegion->GetRenderDC();
03630 
03631         // Use illustrator 3.0 compatible token.
03632         // Any vertical movement is done by BaselineShift
03633         INT32 autokern = 0;
03634         pDC->OutputValue(autokern);
03635         pDC->OutputValue(-(Value.x));
03636         pDC->OutputToken(_T("Tk"));
03637         pDC->OutputNewLine();
03638         return TRUE;
03639     }
03640 #endif
03641     return FALSE;
03642 }
03643 
03644 
03645 /********************************************************************************************
03646 >   Node* KernCode::SimpleCopy()
03647 
03648     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
03649     Created:    21/12/94
03650     Returns:    A copy of the node, or NULL if we are out of memory 
03651     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
03652                 The function is virtual, and must be defined for all derived classes of Node  
03653     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of memory
03654                 error and the function returns NULL. 
03655 ********************************************************************************************/
03656 
03657 Node* KernCode::SimpleCopy()
03658 {
03659     // Make a new BigChar and then copy things into it
03660     KernCode* NodeCopy = new KernCode();
03661 
03662     ERROR1IF(NodeCopy == NULL, NULL, _R(IDE_NOMORE_MEMORY)); 
03663 
03664     if (NodeCopy)
03665         CopyNodeContents(NodeCopy);
03666     
03667     return NodeCopy;
03668 }
03669 
03670 
03671 /***********************************************************************************************
03672 >   void KernCode::CopyNodeContents(KernCode* NodeCopy)
03673 
03674     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
03675     Created:    28/4/93
03676     Outputs:    A copy of this node
03677     Purpose:    This method copies the node's contents to the node pointed to by NodeCopy.
03678     Errors:     An assertion failure will occur if NodeCopy is NULL
03679 ***********************************************************************************************/
03680 
03681 void KernCode::CopyNodeContents(KernCode* NodeCopy)
03682 {
03683     // Ask the base class to do its bit
03684     AbstractTextChar::CopyNodeContents( NodeCopy );
03685     // Copy the rest of the data in here
03686     NodeCopy->Value = Value;
03687 }
03688 
03689 
03690 /***********************************************************************************************
03691 >   void KernCode::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
03692 
03693     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03694     Created:    18/12/2003
03695     Outputs:    -
03696     Purpose:    Polymorphically copies the contents of this node to another
03697     Errors:     An assertion failure will occur if NodeCopy is NULL
03698     Scope:      protected
03699                                      
03700 ***********************************************************************************************/
03701 
03702 void KernCode::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
03703 {
03704     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
03705     ENSURE(IS_A(pNodeCopy, KernCode), "PolyCopyNodeContents given wrong dest node type");
03706 
03707     if (IS_A(pNodeCopy, KernCode))
03708         CopyNodeContents((KernCode*)pNodeCopy);
03709 }
03710 
03711 
03712 
03713 /********************************************************************************************
03714 >   UINT32 KernCode::GetNodeSize() const 
03715 
03716     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
03717     Created:    21/12/94
03718     Returns:    The size of the node in bytes
03719     Purpose:    For finding the size of the node 
03720 ********************************************************************************************/
03721 
03722 UINT32 KernCode::GetNodeSize() const 
03723 {
03724     return (sizeof(KernCode)); 
03725 }
03726 
03727 
03728 /********************************************************************************************
03729 >   void KernCode::GetDebugDetails(StringBase* Str) 
03730 
03731     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
03732     Created:    1/2/95
03733     Outputs:    Str: String giving debug info about the node
03734     Purpose:    For obtaining debug information about the Node. 
03735                 This fn can be deleted before we ship 
03736 ********************************************************************************************/
03737 
03738 void KernCode::GetDebugDetails(StringBase* Str)
03739 {
03740 #if DEBUG_TREE
03741     AbstractTextChar::GetDebugDetails(Str);
03742     String_256 TempStr;
03743         
03744     TempStr._MakeMsg( TEXT( "\r\nKernValue = (#1%u, #2%u)"), Value.x, Value.y);
03745     (*Str) += TempStr;
03746 #endif
03747 }
03748 
03749 /********************************************************************************************
03750 
03751 >   BOOL KernCode::WritePreChildrenWeb(BaseCamelotFilter *pFilter)
03752     BOOL KernCode::WritePreChildrenNative(BaseCamelotFilter *pFilter)
03753 
03754     Author:     Andy_Hayward (Xara Group Ltd) <camelotdev@xara.com>
03755     Created:    10/07/96
03756     Inputs:     pFilter - new file format filter to write record to
03757     Returns:    TRUE if successful, FALSE otherwise
03758     Purpose:    Writes a kern code record to the new file format filter
03759 
03760 ********************************************************************************************/
03761 
03762 BOOL KernCode::WritePreChildrenWeb(BaseCamelotFilter *pFilter)
03763 {
03764 #ifdef DO_EXPORT
03765     return CXaraFileTxtKern::WritePreChildrenWeb(pFilter, this);
03766 #else
03767     return FALSE;
03768 #endif
03769 }
03770 
03771 BOOL KernCode::WritePreChildrenNative(BaseCamelotFilter *pFilter)
03772 {
03773 #ifdef DO_EXPORT
03774     return CXaraFileTxtKern::WritePreChildrenNative(pFilter, this);
03775 #else
03776     return FALSE;
03777 #endif
03778 }
03779 
03780 /********************************************************************************************
03781 >   HorizontalTab::HorizontalTab(Node* ContextNode, AttachNodeDirection Direction)
03782 
03783     Author:     Martin Wuerthner (xara@mw-software.com)
03784     Created:    07/05/06
03785     Inputs:     ContextNode: Pointer to a node which this node is to be attached to.     
03786         
03787                 Direction: 
03788             
03789                 Specifies the direction in which the node is to be attached to the 
03790                 ContextNode. The values this variable can take are as follows: 
03791                                   
03792                 PREV      : Attach node as a previous sibling of the context node
03793                 NEXT      : Attach node as a next sibling of the context node
03794                 FIRSTCHILD: Attach node as the first child of the context node
03795                 LASTCHILD : Attach node as a last child of the context node
03796 
03797     Purpose:    The main HorizontalTab constructor
03798 ********************************************************************************************/
03799 
03800 HorizontalTab::HorizontalTab(Node* ContextNode, AttachNodeDirection Direction)
03801     :AbstractTextChar(ContextNode, Direction)
03802 {
03803 }
03804 
03805 /********************************************************************************************
03806 
03807 >   BOOL HorizontalTab::WritePreChildrenWeb(BaseCamelotFilter *pFilter)
03808     BOOL HorizontalTab::WritePreChildrenNative(BaseCamelotFilter *pFilter)
03809 
03810     Author:     Martin Wuerthner <xara@mw-software.com>
03811     Created:    29/06/06
03812     Inputs:     pFilter - new file format filter to write record to
03813     Returns:    TRUE if successful, FALSE otherwise
03814     Purpose:    Writes a tab record to the new file format filter
03815 
03816 ********************************************************************************************/
03817 
03818 BOOL HorizontalTab::WritePreChildrenWeb(BaseCamelotFilter *pFilter)
03819 {
03820 #ifdef DO_EXPORT
03821     return CXaraFileTxtTab::WritePreChildrenWeb(pFilter, this);
03822 #else
03823     return FALSE;
03824 #endif
03825 }
03826 
03827 BOOL HorizontalTab::WritePreChildrenNative(BaseCamelotFilter *pFilter)
03828 {
03829 #ifdef DO_EXPORT
03830     return CXaraFileTxtTab::WritePreChildrenNative(pFilter, this);
03831 #else
03832     return FALSE;
03833 #endif
03834 }
03835 
03836 /********************************************************************************************
03837 >   UINT32 HorizontalTab::GetNodeSize() const 
03838 
03839     Author:     Martin Wuerthner <xara@mw-software.com>
03840     Created:    29/06/06
03841     Returns:    The size of the node in bytes
03842     Purpose:    For finding the size of the node 
03843 ********************************************************************************************/
03844 
03845 UINT32 HorizontalTab::GetNodeSize() const 
03846 {
03847     return (sizeof(HorizontalTab)); 
03848 }
03849 
03850 void HorizontalTab::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
03851 {
03852     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
03853     ENSURE(IS_A(pNodeCopy, HorizontalTab), "PolyCopyNodeContents given wrong dest node type");
03854 
03855     if (IS_A(pNodeCopy, HorizontalTab))
03856         CopyNodeContents((HorizontalTab*)pNodeCopy);
03857 }
03858 
03859 Node* HorizontalTab::SimpleCopy()
03860 {
03861     // Make a new HorizontalTab and then copy things into it
03862     HorizontalTab* NodeCopy = new HorizontalTab();
03863 
03864     ERROR1IF(NodeCopy == NULL, NULL, _R(IDE_NOMORE_MEMORY)); 
03865 
03866     if (NodeCopy) CopyNodeContents( NodeCopy );
03867     
03868     return NodeCopy;
03869 }
03870 
03871 /*******************************************************************************************
03872 >   BOOL HorizontalTab::ExportRender(RenderRegion* pRegion)
03873 
03874     Author:     Martin Wuerthner <xara@mw-software.com>
03875     Created:    18/07/06
03876     Inputs:     pRegion - points to the export render region
03877     Returns:    TRUE if rendered OK (FALSE=>use normal rendering)
03878     Purpose:    This function is called when the render function passes through this node
03879                 It outputs the  Text Object start and end tokens
03880     See also:   KernCode::ExportRender, on which this routine is based
03881 ********************************************************************************************/
03882 BOOL HorizontalTab::ExportRender(RenderRegion* pRegion)
03883 {
03884     // a tab is exported as a horizontal kern code
03885 #if EXPORT_TEXT
03886     if (pRegion->IsKindOf(CC_RUNTIME_CLASS(EPSRenderRegion)))
03887     {
03888         // Output any valid text attributes necessary
03889         ((EPSRenderRegion*)pRegion)->GetValidPathAttributes();
03890         ((EPSRenderRegion*)pRegion)->GetValidTextAttributes();
03891 
03892         EPSExportDC *pDC=(EPSExportDC*)pRegion->GetRenderDC();
03893 
03894         // Use illustrator 3.0 compatible token.
03895         INT32 autokern = 0;
03896         pDC->OutputValue(autokern);
03897         pDC->OutputValue(GetCharWidth());
03898         pDC->OutputToken(_T("Tk"));
03899         pDC->OutputNewLine();
03900         return TRUE;
03901     }
03902 #endif
03903     return FALSE;
03904 }

Generated on Sat Nov 10 03:46:09 2007 for Camelot by  doxygen 1.4.4