00001 // $Id: fthrattr.cpp 1738 2006-09-04 15:23:34Z luke $ 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 #include "camtypes.h" 00100 #include "fthrattr.h" 00101 00102 // Algorithms and node classes used for creating feather transp mask 00103 #include "nodecntr.h" // NodeContour::GenerateContourPathForNode 00104 //#include "doccolor.h" // DocColour and COLOUR_BLACK 00105 #include "lineattr.h" // AttrLineWidth 00106 //#include "fillval.h" // BitmapFillAttribute, TransparencyFillAttribute - in camtypes.h [AUTOMATICALLY REMOVED] 00107 #include "offscrn.h" // GRenderRegionWrapper 00108 00109 // Tags, messages and other UI stuff 00110 //#include "attrmgr.h" // enum AttrIndex - in camtypes.h [AUTOMATICALLY REMOVED] 00111 //#include "feather.h" // _R(IDS_FEATHER_ATTR_ID) 00112 //#include "mario.h" // _R(IDE_NOMORE_MEMORY) 00113 00114 // RenderRegions 00115 #include "grndrgn.h" // GRenderRegion 00116 00117 // Fiddling with bitmaps - offscreen and feather transp bmps 00118 //#include "bitmap.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00119 #include "oilbitmap.h" 00120 00121 // Caching contour path and updating on pseudo AllowOps 00122 #include "opfeathr.h" // RegenerateFeatherContourAction 00123 #include "objchge.h" // ObjChange and AllowOp stuff 00124 #include "transop.h" // TransOperation - optimise which operations trigger recontour 00125 00126 // Blending (creating dynamic attributes) 00127 #include "blendatt.h" // BlendAttrParam 00128 #include "nodeblnd.h" // NodeBlend 00129 #include "attrmap.h" // CCAttrMap 00130 #include "nodepath.h" 00131 00132 // Special cases 00133 #include "nodedoc.h" // NodeDocument 00134 //#include "grndclik.h" // GRenderClick 00135 //#include "grndbrsh.h" // GRenderBrush 00136 00137 // Saving and loading 00138 #include "cxftags.h" 00139 //#include "cxfdefs.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00140 //#include "cxfrec.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00141 00142 // Printing 00143 //#include "saveeps.h" 00144 00145 // Quality settings 00146 #include "qualattr.h" 00147 00148 #include "nodemold.h" 00149 //#include "bitmapcache.h" 00150 #include "pathndge.h" 00151 00152 //DECLARE_SOURCE("$Revision: 1738 $") 00153 00154 CC_IMPLEMENT_DYNCREATE( FeatherAttrValue, OffscreenAttrValue ) 00155 CC_IMPLEMENT_DYNAMIC( AttrFeather, NodeAttribute ) 00156 CC_IMPLEMENT_DYNAMIC( FeatherRecordHandler,CamelotRecordHandler ) 00157 00158 // Declare smart memory handling in Debug builds 00159 #define new CAM_DEBUG_NEW 00160 00161 // Uncomment any of the following to attach the associated bitmap into the bitmap gallery 00162 //#define DEBUG_ATTACH_PRECONV_OFFSCREEN_BMP 00163 //#define DEBUG_ATTACH_OFFSCREEN_BMP 00164 //#define DEBUG_ATTACH_SILHOUETTE_BMP 00165 //#define DEBUG_ATTACH_FEATHER_BMP 00166 //#define DEBUG_RENDER_OFFSCREEN_BMP_WITHOUT_MASK 00167 00168 // The maximum feather size which we allow the user to play with. 00169 // If you're thinking of changing this, PLEASE BE AWARE that other/older versions 00170 // of the app will cap feathers loaded/pasted into them at THEIR maximum value. 00171 // As of 30/01/2001, GDraw's maximum blur size is a 200 pixel diameter. 00172 // I'm choosing a user limit of 50 pixels diameter at 96dpi (100% zoom on most systems) 00173 // which gives 50 * (72000 / 96) = 37500 millipoints. 00174 // 00175 const MILLIPOINT FeatherAttrValue::MaxUserFeatherSize = 37500; 00176 00177 00179 // 00180 // Helper functions 00181 // 00183 // TRUE if map contains all necessary line attrs for NodePath::MakeNodePathFromAttributes to succeed 00184 // FALSE otherwise 00185 BOOL CheckLineAttrs(CCAttrMap* pAttrMap) 00186 { 00187 void* ptr = NULL; 00188 return ( 00189 pAttrMap->Lookup( CC_RUNTIME_CLASS(AttrLineWidth),(void *&)ptr) && 00190 pAttrMap->Lookup( CC_RUNTIME_CLASS(AttrStartArrow),(void *&)ptr) && 00191 pAttrMap->Lookup( CC_RUNTIME_CLASS(AttrEndArrow),(void *&)ptr) && 00192 pAttrMap->Lookup( CC_RUNTIME_CLASS(AttrJoinType),(void *&)ptr) && 00193 pAttrMap->Lookup( CC_RUNTIME_CLASS(AttrStartCap),(void *&)ptr) && 00194 pAttrMap->Lookup( CC_RUNTIME_CLASS(AttrDashPattern),(void *&)ptr) 00195 ); 00196 } 00197 00198 BOOL MakeLineAttributeCompleteForContouring(Node* Context, Node* NodeToModify, CCAttrMap* pAttrMap) 00199 { 00200 AttrLineWidth * pAttrLineWidth = NULL; 00201 AttrStartArrow * pAttrStartArrow = NULL; 00202 AttrEndArrow * pAttrEndArrow = NULL; 00203 AttrJoinType * pAttrJoinType = NULL; 00204 AttrStartCap * pAttrStartCap = NULL; 00205 AttrDashPattern * pAttrDashPattern = NULL; 00206 AttrStrokeColour* pAttrStrokeColour = NULL; 00207 00208 // get all the attributes out of the attribute map 00209 pAttrMap->Lookup( CC_RUNTIME_CLASS(AttrLineWidth),(void *&)pAttrLineWidth); 00210 if(pAttrLineWidth) 00211 pAttrLineWidth->AttachNode(Context,FIRSTCHILD,FALSE,FALSE); 00212 00213 pAttrMap->Lookup( CC_RUNTIME_CLASS(AttrStartArrow),(void *&)pAttrStartArrow); 00214 if (pAttrStartArrow) 00215 pAttrStartArrow->AttachNode(Context,FIRSTCHILD,FALSE,FALSE); 00216 00217 pAttrMap->Lookup( CC_RUNTIME_CLASS(AttrEndArrow),(void *&)pAttrEndArrow); 00218 if (pAttrEndArrow) 00219 pAttrEndArrow->AttachNode(Context,FIRSTCHILD,FALSE,FALSE); 00220 00221 pAttrMap->Lookup( CC_RUNTIME_CLASS(AttrJoinType),(void *&)pAttrJoinType); 00222 if(pAttrJoinType) 00223 pAttrJoinType->AttachNode(Context,FIRSTCHILD,FALSE,FALSE); 00224 00225 pAttrMap->Lookup( CC_RUNTIME_CLASS(AttrStartCap),(void *&)pAttrStartCap); 00226 if(pAttrStartCap) 00227 pAttrStartCap->AttachNode(Context,FIRSTCHILD,FALSE,FALSE); 00228 00229 pAttrMap->Lookup( CC_RUNTIME_CLASS(AttrDashPattern),(void *&)pAttrDashPattern); 00230 if(pAttrDashPattern) 00231 pAttrDashPattern->AttachNode(Context,FIRSTCHILD,FALSE,FALSE); 00232 00233 pAttrMap->Lookup( CC_RUNTIME_CLASS(AttrStrokeColour),(void *&)pAttrStrokeColour); 00234 if(pAttrStrokeColour) 00235 pAttrStrokeColour->AttachNode(Context,FIRSTCHILD,FALSE,FALSE); 00236 00237 if( pAttrLineWidth && pAttrStartArrow && pAttrEndArrow && pAttrJoinType && 00238 pAttrStartCap && pAttrDashPattern && pAttrStrokeColour) 00239 { 00240 Node* pLastChild = Context->FindLastChild(); 00241 NodeToModify->AttachNode(pLastChild,NEXT,FALSE,FALSE); // dynamic attrs are copies, so we are free to modify them 00242 return TRUE; 00243 } 00244 else 00245 { 00246 return FALSE; 00247 } 00248 } 00249 00250 00252 // 00253 // AttributeValue classes 00254 // 00256 00257 /******************************************************************************************** 00258 > FeatherAttrValue:: 00259 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 00260 Created: 24/01/2000 00261 Purpose: This constructor is called in three different scenarios:- 00262 1 - to initialise attrvalue tables 00263 2 - to create a new feather to apply to a selected node by an OpFeather operation 00264 3 - in the process of creating a simple copy of an exisiting Feather attr 00265 ie. either a default attr from the attr table (to attach to a new node) 00266 or a clone of an AttrFeather __node__ (ie as part of OpClone) 00267 The initialisation process will always create 0 width default feather attributes 00268 and hence will always attach 0 width feathers as the documents base feather attr. 00269 00270 SeeAlso: 00271 ********************************************************************************************/ 00272 FeatherAttrValue::FeatherAttrValue() 00273 { 00274 // m_Profile = CProfileBiasGain() // Defaults to this 00275 m_GapSize = DEFAULT_GAP_TOLERANCE_MP; 00276 m_FeatherSize = 0; // Document base Feather has 0 feather size. 00277 // The doc base feather is created when camelot 00278 // initialises a new document. 00279 // The default feather applied to each new object 00280 // is also setup by this constructor. 00281 m_pOuterContour = NULL; 00282 m_bCached = FALSE; 00283 } 00284 00285 /******************************************************************************************** 00286 > FeatherAttrValue:: 00287 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 00288 Created: 24/01/2000 00289 Purpose: Free outer contour path if we have one 00290 SeeAlso: 00291 ********************************************************************************************/ 00292 FeatherAttrValue::~FeatherAttrValue() 00293 { 00294 // only m_pOuterContour may be left because it is cached 00295 if (m_pOuterContour != NULL) 00296 { 00297 delete m_pOuterContour; 00298 m_pOuterContour = NULL; 00299 } 00300 } 00301 00302 /******************************************************************************************** 00303 > FeatherAttrValue:: 00304 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 00305 Created: 24/01/2000 00306 Purpose: 00307 SeeAlso: 00308 ********************************************************************************************/ 00309 BOOL FeatherAttrValue::Init() 00310 { 00311 // Default to no feathering 00312 FeatherAttrValue *pAttr = new FeatherAttrValue; 00313 if (pAttr==NULL) 00314 // error message has already been set by new 00315 return FALSE; 00316 00317 pAttr->SetDefault(); 00318 00319 UINT32 AttrID = AttributeManager::RegisterDefaultAttribute(CC_RUNTIME_CLASS(NodeRenderableInk), 00320 pAttr); 00321 00322 ERROR2IF(AttrID == ATTR_BAD_ID, FALSE, "Bad ID when Initialising FeatherAttrValue"); 00323 ERROR2IF(AttrID != ATTR_FEATHER, FALSE, "Incorrect ID for FeatherAttrValue"); 00324 00325 return TRUE; 00326 } 00327 00328 /******************************************************************************************** 00329 > FeatherAttrValue:: 00330 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 00331 Created: 24/01/2000 00332 Purpose: 00333 SeeAlso: 00334 TODO: Determine whether to copy bitmap or just pointer to it 00335 ********************************************************************************************/ 00336 void FeatherAttrValue::SimpleCopy(AttributeValue *pVal) 00337 { 00338 ERROR3IF(!pVal->IS_KIND_OF(FeatherAttrValue), "Incorrect runtime class passed to FeatherAttrValue::SimpleCopy"); 00339 FeatherAttrValue* pFthr = (FeatherAttrValue*) pVal; 00340 00341 m_Profile = pFthr->m_Profile; 00342 SetFeatherSize(pFthr->GetFeatherSize()); 00343 m_GapSize = pFthr->m_GapSize; 00344 00345 // NOTE! Don't copy m_outerContour because callers assume that this will 00346 // not be copied and rely on it being regenerated on demand. Urgh! 00347 // Remember to copy or blank cached path data without leaking memory... 00348 if (m_pOuterContour) 00349 delete m_pOuterContour; 00350 m_pOuterContour = NULL; 00351 /* 00352 Path* pSrcPath = pFthr->GetOuterContour(); 00353 if (pSrcPath) 00354 { 00355 m_pOuterContour = new Path(); 00356 m_pOuterContour->Initialise(pSrcPath->GetNumCoords()); 00357 m_pOuterContour->CopyPathDataFrom(pSrcPath); 00358 } 00359 */ 00360 // preserves default flag to avoid confusion when copying CCAttrMaps 00361 GeometryLinkedAttrValue::SimpleCopy(pVal); 00362 } 00363 00364 /******************************************************************************************** 00365 > FeatherAttrValue:: 00366 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 00367 Created: 24/01/2000 00368 Purpose: 00369 SeeAlso: 00370 ********************************************************************************************/ 00371 NodeAttribute* FeatherAttrValue::MakeNode() 00372 { 00373 AttrFeather* pNode = new AttrFeather(); 00374 pNode->Value.SimpleCopy(this); 00375 return pNode; 00376 } 00377 00378 /******************************************************************************************** 00379 > FeatherAttrValue:: 00380 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 00381 Created: 24/01/2000 00382 Purpose: 00383 SeeAlso: 00384 ********************************************************************************************/ 00385 BOOL FeatherAttrValue::Blend(BlendAttrParam* pBlendParam) 00386 { 00387 // First get the fill that we are blending to 00388 FeatherAttrValue* OtherFthr = (FeatherAttrValue*)pBlendParam->GetOtherAttrVal(); 00389 00390 if(IsDefaultFlagSet() && OtherFthr->IsDefaultFlagSet()) 00391 { 00392 // no blending required 00393 // pBlendParam->SetBlendedAttrVal(NULL); 00394 return FALSE; 00395 } 00396 00397 00398 FeatherAttrValue* pNewAttr = new FeatherAttrValue; 00399 00400 if (pNewAttr == NULL) 00401 { 00402 // Fail if we couldn't create the new fill 00403 pBlendParam->SetBlendedAttrVal(NULL); 00404 return FALSE; 00405 } 00406 00407 // and what point along the blend we are at 00408 double Ratio = pBlendParam->GetBlendRatio(); 00409 00410 // blend m_pFeatherWidth 00411 MILLIPOINT Start = GetFeatherSize(); 00412 MILLIPOINT End = OtherFthr->GetFeatherSize(); 00413 pNewAttr->SetFeatherSize( (MILLIPOINT) ( Start + Ratio*(End - Start) ) ); 00414 00415 // blend m_Profile 00416 CProfileBiasGain BiasGain = m_Profile; // the first fills profile 00417 CProfileBiasGain OtherBiasGain = OtherFthr->m_Profile; // the other fills profile 00418 if (!(BiasGain == OtherBiasGain)) 00419 { 00420 /* From other blend Profiles code 00421 double InvRatio = 1 - Ratio; 00422 double BlendedBias = (BiasGain.GetBias () * InvRatio) + (OtherBiasGain.GetBias () * Ratio); 00423 double BlendedGain = (BiasGain.GetGain () * InvRatio) + (OtherBiasGain.GetGain () * Ratio); 00424 */ 00425 double StartBias = m_Profile.GetBias(); double EndBias = OtherBiasGain.GetBias(); 00426 double StartGain = m_Profile.GetGain(); double EndGain = OtherBiasGain.GetGain(); 00427 double BlendedBias = StartBias + ((EndBias - StartBias) * Ratio); 00428 double BlendedGain = StartGain + ((EndGain - StartGain) * Ratio); 00429 00430 pNewAttr->m_Profile.SetBias (BlendedBias); 00431 pNewAttr->m_Profile.SetGain (BlendedGain); 00432 } 00433 00434 // Set the new fill as the blended attribute 00435 pBlendParam->SetBlendedAttrVal(pNewAttr); 00436 00437 return TRUE; 00438 } 00439 00440 /******************************************************************************************** 00441 > FeatherAttrValue:: 00442 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 00443 Created: 24/01/2000 00444 Purpose: Put the GRenderRegion offscreen rendering system into play (provided we're 00445 dealing with a real feather attribute and not just the base doc attr). 00446 SeeAlso: GRenderRegion::SetFeathering, FeatherAttrValue::OffscreenRenderingCompleted() 00447 ********************************************************************************************/ 00448 void FeatherAttrValue::Render(RenderRegion *pRender, BOOL Temp) 00449 { 00450 // TRACEUSER( "Gerry", _T("Rendering feather attribute of %d (0x%08x)\n"), GetFeatherSize(), this); 00451 00452 // Karim 20/07/2000 00453 // currently, we only generate an offscreen bitmap for GRenderRegions, although we are 00454 // 'rendered' into all RR's. therefore we must quit quietly if pRender is not a GRR. 00455 // Gerry 12/01/2005 00456 // This is no longer true. We need to render this into all types of render region 00457 // so the code has been removed 00458 00459 // if (!pRender->IS_KIND_OF(GRenderRegion)) 00460 // return; 00461 00462 // if the feather size is zero, then quit now - no feathering is necessary. 00463 MILLIPOINT mpFeather = GetFeatherSize(); 00464 if (mpFeather == 0) 00465 return; 00466 00467 // ... and shout out if the feather size is negative - something is WRONG! 00468 else if (mpFeather < 0) 00469 { 00470 ERROR3("Negative feather size! What's going on?"); 00471 return; 00472 } 00473 00474 // you would place code here if you need to affect currentAttrs table 00475 // also alloc any mem you need for the duration of the rendering cycle 00476 OffscreenAttrValue::Render(pRender, Temp); 00477 } 00478 00479 /******************************************************************************************** 00480 > FeatherAttrValue:: 00481 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 00482 Created: 24/01/2000 00483 Purpose: 00484 SeeAlso: GRenderRegion::RestoreGDrawBitmap 00485 ********************************************************************************************/ 00486 void FeatherAttrValue::Restore(RenderRegion *pRegion, BOOL Temp) 00487 { 00488 //TRACEUSER( "Phil", _T("Restoring feather attribute of %d (0x%08x)\n"), GetFeatherSize(), this); 00489 // NB this function doesn't need to be implemented - the base class handles everything 00490 // Just showing you where to put extra code 00491 00492 OffscreenAttrValue::Restore(pRegion, Temp); 00493 } 00494 00495 /******************************************************************************************** 00496 > FeatherAttrValue:: 00497 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 00498 Created: 24/01/2000 00499 Purpose: The random nature of generation of redraw cliprect coordinates means that we 00500 may sometimes be asked to redraw a really thin sliver of the feathered object. 00501 This is a problem for the convolution code if the sliver is thinner (in height 00502 or width) than 2 pixels. 00503 SeeAlso: GRenderRegion::RestoreGDrawBitmap 00504 ********************************************************************************************/ 00505 void FeatherAttrValue::GetMinimumOffscreenBmpDimensions(UINT32* RequiredWidth, UINT32* RequiredHeight) 00506 { 00507 *RequiredWidth = 2; 00508 *RequiredHeight = 2; 00509 } 00510 00511 /******************************************************************************************** 00512 > FeatherAttrValue:: 00513 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 00514 Created: 24/01/2000 00515 Purpose: To allow the offscreen attribute to perform whatever processing it requires on 00516 the bitmap copy of the subtree rooted at m_pLinkedNode and then draw into the partially 00517 rendered bitmap of the predecessors of m_pLinkedNode 00518 00519 Notes: 1) This function gets called when the RR exits the context under which the 00520 attribute was Render()ed (ie after completeing a DrawPath("this->m_pLinkedNode->Path"). 00521 2) The offscreen rendering system (implemented in GRenderRegion) has already 00522 restored the clip rect and GDraw bitmap and matrix state of the previous offscreen 00523 attribute. 00524 This function is actually being called by the RenderRegion in the process of 00525 Restore()ing this previous offscreen attribute (ie the process of taking the attribute 00526 which is sitting on top of the attribute context stack, and restoring it to the 00527 CurrentAttrs table). 00528 So at this point the GRenderRegion and GDraw context are back the way they 00529 were before "this" offscreen attribute was Render()ed. 00530 3) m_pOffscreenBmpBits points to the buffer holding the fully rendered bitmap 00531 of the subtree rooted at m_pLinkedNode 00532 4) Any transparency attribute existing at the same level as this offscreen attr 00533 (ie attached to "this->m_pLinkedNode") will already have affected the bitmap in 00534 "this->m_pOffscreenBmpBits". 00535 5) You don't need to delete the bitmap pointers UNLESS you installed "this" attribute 00536 as a non-temporary attribute in the Render() function (ie SetFeathering(this, FALSE..)). 00537 If it is a temporary attribute (which is the default) then the deconstructor will handle 00538 the deallocation of the memory pointed to by m_pOffscreenBmpBits & m_pOffscreenBmpInfo 00539 SeeAlso: GRenderRegion::RestoreFeathering(); ~FeatherAttrValue(); RenderRegion::RestoreAttribute() 00540 FeatherAttrValue::Render(), GRenderRegion::SetFeathering() 00541 ********************************************************************************************/ 00542 void FeatherAttrValue::OffscreenRenderingCompleted(RenderRegion *pRender, LPBITMAPINFO lpBitmapInfo, LPBYTE lpBits, DocRect BitmapRect) 00543 { 00544 // TRACEUSER( "Gerry", _T("Feather attribute OffscreenRenderingCompleted (0x%08x)\n"), this); 00545 // TRACEUSER( "Phil", _T("Feather attribute OffscreenRenderingCompleted (0x%08x)\n"), this); 00546 00547 // TEMP BODGE 00548 m_OffBB = BitmapRect; 00549 00550 // Karim 20/07/2000 00551 // currently, we only generate an offscreen bitmap for GRenderRegions, although we are 00552 // 'rendered' into all RR's. therefore we must quit quietly if pRender is not a GRR. 00553 if (!pRender->IS_KIND_OF(GRenderRegion)) 00554 return; 00555 00556 GRenderRegion* pGRR = (GRenderRegion*)pRender; 00557 RRCaps Caps; 00558 pGRR->GetRenderRegionCaps(&Caps); 00559 if (!Caps.DoesRegionDoAll()) 00560 return; 00561 00562 // Karim 19/10/2000 00563 // The offscreen rendering may possibly fail, 00564 // in which case all we can do now is quit. 00565 if (lpBitmapInfo == NULL || lpBits == NULL) 00566 { 00567 // ERROR3("FeatherAttrValue::OffscreenRenderingCompleted; don't have any bitmap info!"); 00568 return; 00569 } 00570 00571 double fScaledPixelWidth = pGRR->GetScaledPixelWidthDouble(); 00572 // TRACEUSER( "Gerry", _T("ScaledPixelWidth = %f\n"), fScaledPixelWidth); 00573 double pixBlurDiameter = GetFeatherPixelSize(fScaledPixelWidth); 00574 // TRACEUSER( "Gerry", _T("BlurDiameter = %f\n"), pixBlurDiameter); 00575 00576 // Setup path to draw 00577 Path* pPathToDraw = GetVisibleBoundingPath(); 00578 if (pPathToDraw == NULL) 00579 { 00580 ERROR3("FeatherAttrValue::OffscreenRenderingCompleted; Couldn't create path!"); 00581 return; 00582 } 00583 00585 // Create the bitmap fill containing the offscreen rendition of the objects to feather. 00587 00588 CWxBitmap *wBitmap = NULL; 00589 KernelBitmap *OffscreenBitmap = NULL; 00590 00591 // TRACEUSER( "Gerry", _T("Offscreen size = (%d, %d)\n"), pOffBmpHdr->biWidth, pOffBmpHdr->biHeight); 00592 00593 // Create a Kernel bitmap from the bmp data. 00594 wBitmap = new CWxBitmap(lpBitmapInfo, lpBits); 00595 OffscreenBitmap = new KernelBitmap(wBitmap,TRUE); 00596 00597 // Setup the bitmap fill. 00598 // Since the offscreen bitmap has been plotted using the full rendering matrix 00599 // which may include a rotation during printing, we must now force GDraw to 00600 // render it using the same rotation (see GRenderRegion::AllocateOffScreenState) 00601 BitmapFillAttribute BmpFill; 00602 ANGLE rot; 00603 Matrix m = pGRR->GetMatrix(); 00604 m.Decompose(NULL, NULL, &rot, NULL, NULL); 00605 if (rot==0) 00606 // CreateBitmapFill(OffscreenBitmap, &m_OffBB, &BmpFill); 00607 CreateBitmapFill(OffscreenBitmap, &BitmapRect, &BmpFill); 00608 else 00609 // CreateBitmapFillRot90(OffscreenBitmap, &m_OffBB, &BmpFill); 00610 CreateBitmapFillRot90(OffscreenBitmap, &BitmapRect, &BmpFill); 00611 // No other rotations are currently possible... 00612 00613 // DEBUG: add offscreen bmp to bitmap gallery 00614 #ifdef DEBUG_ATTACH_OFFSCREEN_BMP 00615 OffscreenBitmap->AttachDebugCopyToCurrentDocument("Offscreen Bitmap"); 00616 #endif 00617 00618 00620 // Create the feather bitmap transparency mask. 00622 00623 KernelBitmap* FeatherBitmap = CreateFeatherBitmap(pGRR, pixBlurDiameter); 00624 00625 BitmapTranspFillAttribute BmpTranspFill; 00626 if (FeatherBitmap != NULL) 00627 { 00628 CreateBitmapTranspFill(FeatherBitmap, &m_drFeatherBB, &BmpTranspFill); 00629 } 00630 00631 00633 // Render the bitmaps together for the final feathered result. 00634 // 00635 // If we had any problems creating the feather bitmap transparency, or if our debug 00636 // rendering is enabled, then we try to fail gracefully by rendering just the 00637 // offscreen bitmap. Note that this bitmap will only have an alpha channel if some of 00638 // the feathered objects require it, and will have a white background otherwise. 00640 pGRR->SaveContext(); 00641 00642 // DEBUG: see note above. 00643 #ifndef DEBUG_RENDER_OFFSCREEN_BMP_WITHOUT_MASK 00644 if (FeatherBitmap != NULL) 00645 pGRR->RenderBitmapWithTransparency(pPathToDraw, &BmpFill, &BmpTranspFill); 00646 #else 00647 pGRR->RenderBitmapWithTransparency(pPathToDraw, &BmpFill, NULL); 00648 #endif 00649 00650 pGRR->RestoreContext(); 00651 00653 // Clean up all our data structures. 00655 if (FeatherBitmap != NULL) 00656 { 00657 delete FeatherBitmap; 00658 FeatherBitmap = NULL; 00659 } 00660 00661 if (pPathToDraw != NULL) 00662 { 00663 delete pPathToDraw; 00664 pPathToDraw = NULL; 00665 } 00666 00667 FreeDIB(lpBitmapInfo, lpBits, NULL, FALSE); 00668 00669 // makes ~CWxBitmap() think that bmp HasBeenDeleted(). 00670 wBitmap->BMBytes = ( (CWxBitmap *)OILBitmap::Default )->BMBytes; 00671 delete OffscreenBitmap; 00672 } 00673 00674 00675 00676 00677 /******************************************************************************************** 00678 00679 > virtual BOOL FeatherAttrValue::CreateFeatherTransp( GRenderRegion* pGRR, 00680 Path* pPath, 00681 double dPixelWidth, 00682 BitmapTranspFillAttribute** ppFeatherTransp, 00683 KernelBitmap** ppFeatherBitmap 00684 ) 00685 00686 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 00687 Created: 05/08/2005 00688 Inputs: pPath - Pointer to path to be feathered 00689 dPixelWidth - Pixel width in millipoints 00690 Outputs: pFeatherTransp - Pointer to transparency attribute for feathering 00691 pFeatherBitmap - POinter to feather bitmap used in transparency attribute 00692 Returns: TRUE if it worked 00693 FALSE otherwise 00694 Purpose: Create the feather transparency attribute using the supplied path /without/ 00695 reference to any surrounding nodes in the tree 00696 Used by NodeBitmap::GetDirectBitmap 00697 00698 ********************************************************************************************/ 00699 BOOL FeatherAttrValue::CreateFeatherTransp( GRenderRegion* pGRR, 00700 Path* pPath, 00701 double dPixelWidth, 00702 BitmapTranspFillAttribute** ppFeatherTransp, 00703 KernelBitmap** ppFeatherBitmap 00704 ) 00705 { 00706 double dpixBlurDiameter = GetFeatherPixelSize(dPixelWidth); 00707 LPBYTE pFeatherBits = NULL; 00708 LPBITMAPINFO pFeatherInfo = NULL; 00709 KernelBitmap* kbmpFeather = NULL; 00710 DocRect rectBounds = pPath->GetBoundingRect(); 00711 // UINT32 pixWidth = UINT32(floor( rectBounds.Width() / dPixelWidth + 0.5 )); 00712 // UINT32 pixHeight = UINT32(floor( rectBounds.Height() / dPixelWidth + 0.5 )); 00713 00714 // ------------------------------------------------------------------- 00715 // First make the silhouette bitmap 00716 // create the silhouette bitmap. 00717 m_OffBB = rectBounds; 00718 m_GapSize = 0; 00719 LPBYTE pSilhouetteBits; 00720 LPBITMAPINFO pSilhouetteInfo = CreateSilhouetteBitmap(pGRR, &pSilhouetteBits, pPath); 00721 00722 if (pSilhouetteInfo==NULL || pSilhouetteBits==NULL) 00723 return FALSE; 00724 00725 // ------------------------------------------------------------------- 00726 // Next blur the silhouette bitmap to obtain the feather bitmap. 00727 pFeatherInfo = CBitmapShadow::Feather8BppBitmap( 00728 dpixBlurDiameter, 00729 pSilhouetteInfo, 00730 pSilhouetteBits, 00731 &pFeatherBits 00732 ); 00733 00734 // If Feather8BPP returned the same bitmap, clear silhouette pointers so we don't 00735 // deallocate the bitmap at the end of this function... 00736 if (pFeatherInfo == pSilhouetteInfo) 00737 { 00738 pSilhouetteInfo = NULL; 00739 pSilhouetteBits = NULL; 00740 } 00741 00742 if (pFeatherInfo != NULL && pFeatherBits != NULL) 00743 { 00744 CWxBitmap* wbmpFeather = new CWxBitmap(pFeatherInfo, pFeatherBits); 00745 kbmpFeather = new KernelBitmap(wbmpFeather, TRUE); 00746 00747 SetupFeatherBitmapPalette(kbmpFeather); 00748 00749 *ppFeatherBitmap = kbmpFeather; 00750 } 00751 00752 // We don't need the silhouette bitmap any more 00753 if (pSilhouetteInfo != NULL && pSilhouetteBits != NULL) 00754 FreeDIB(pSilhouetteInfo, pSilhouetteBits); 00755 00756 // If we failed to create the blurred bitmap then exit now 00757 if (*ppFeatherBitmap==NULL) 00758 return FALSE; 00759 00760 // ---------------------------------------------------------------------- 00761 // Now make the transparency attribute to carry the feather bitmap 00762 *ppFeatherTransp = new BitmapTranspFillAttribute; 00763 if (*ppFeatherTransp==NULL) 00764 { 00765 delete *ppFeatherBitmap; 00766 *ppFeatherBitmap = NULL; 00767 return FALSE; 00768 } 00769 00770 CreateBitmapTranspFill(*ppFeatherBitmap, &rectBounds, *ppFeatherTransp); 00771 00772 return TRUE; 00773 } 00774 00775 00776 00777 00778 /******************************************************************************************** 00779 00780 > virtual BOOL FeatherAttrValue::DoesOffscreenBmpRequireTransp(GRenderRegion* pGRR) 00781 00782 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 00783 Created: 19/11/2000 00784 00785 Inputs: pGRR the RR which the feather will be rendered into. 00786 00787 Purpose: Override of OffscreenAttrValue virtual function. 00788 Feathers always require a transparent bitmap if their feather size is less 00789 than a certain value, otherwise they use the default implementation. 00790 00791 This prevents white artifacts on small feather sizes. 00792 00793 See also: CreateSilhouetteBitmap, OffscreenAttrValue::DoesOffscreenBmpRequireTransp. 00794 00795 ********************************************************************************************/ 00796 BOOL FeatherAttrValue::DoesOffscreenBmpRequireTransp(GRenderRegion* pGRR) 00797 { 00798 // In conjunction with DoesOffscreenBMPCaptureBackground this function should 00799 // now return FALSE always so that the offscreen bitmap does not attempt to 00800 // capture transparency info but rather captures the RESULTS of transparency... 00801 if (DoesOffscreenBMPCaptureBackground()) 00802 return FALSE; 00803 00804 if (pGRR == NULL) 00805 { 00806 ERROR3("FeatherAttrValue::DoesOffscreenBmpRequireTransp; Invalid params!"); 00807 return FALSE; 00808 } 00809 00810 const double ScaledPixelWidth = pGRR->GetScaledPixelWidthDouble(); 00811 const double FeatherPixelSize = GetFeatherPixelSize(ScaledPixelWidth); 00812 00813 return (FeatherPixelSize < 2*MIN_BLUR_DIAMETER) ? TRUE : 00814 OffscreenAttrValue::DoesOffscreenBmpRequireTransp(pGRR) ; 00815 } 00816 00817 00818 00819 /******************************************************************************************** 00820 00821 > KernelBitmap* FeatherAttrValue::CreateFeatherBitmap(GRenderRegion* pGRR, 00822 double pixBlurDiameter) 00823 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 00824 Created: 19 September 2000 00825 Inputs: pGRR the GRenderRegion to base the silhouette bitmap on. 00826 pixBlurDiameter feather blur width, in pixels (can be non-integer). 00827 00828 Returns: A ptr to a KernelBitmap containing the transparency mask part of the feather. 00829 00830 Purpose: Create the feather bitmap-transparency mask. 00831 00832 See Also: CreateSilhouetteBitmap(). 00833 00834 ********************************************************************************************/ 00835 KernelBitmap* FeatherAttrValue::CreateFeatherBitmap(GRenderRegion* pGRR, 00836 double pixBlurDiameter) 00837 { 00838 // will contain the feather bitmap transparency mask. 00839 LPBYTE pFeatherBits = NULL; 00840 LPBITMAPINFO pFeatherInfo = NULL; 00841 KernelBitmap* kbmpFeather = NULL; 00842 00843 // create the silhouette bitmap. 00844 LPBYTE pSilhouetteBits; 00845 LPBITMAPINFO pSilhouetteInfo = CreateSilhouetteBitmap(pGRR, &pSilhouetteBits); 00846 00847 if (pSilhouetteInfo != NULL && pSilhouetteBits != NULL) 00848 { 00849 // TRACEUSER( "Gerry", _T("Silhouette size = (%d, %d)\n"), pSilhouetteInfo->bmiHeader.biWidth, pSilhouetteInfo->bmiHeader.biHeight); 00850 00851 // blur the silhouette bitmap to obtain the feather bitmap. 00852 pFeatherInfo = CBitmapShadow::Feather8BppBitmap( 00853 pixBlurDiameter, 00854 pSilhouetteInfo, 00855 pSilhouetteBits, 00856 &pFeatherBits 00857 ); 00858 00859 // If Feather8BPP returned the same bitmap, clear silhouette pointers so we don't 00860 // deallocate the bitmap at the end of this function... 00861 if (pFeatherInfo == pSilhouetteInfo) 00862 { 00863 pSilhouetteInfo = NULL; 00864 pSilhouetteBits = NULL; 00865 } 00866 00867 if (pFeatherInfo != NULL && pFeatherBits != NULL) 00868 { 00869 // TRACEUSER( "Gerry", _T("Feather size = (%d, %d)\n"), pFeatherInfo->bmiHeader.biWidth, pFeatherInfo->bmiHeader.biHeight); 00870 CWxBitmap* wbmpFeather = new CWxBitmap(pFeatherInfo, pFeatherBits); 00871 kbmpFeather = new KernelBitmap(wbmpFeather, TRUE); 00872 00873 SetupFeatherBitmapPalette(kbmpFeather); 00874 } 00875 } 00876 00878 // 00879 // DEBUG: add copies of the silhouette and feather bitmaps to the bitmap gallery. 00880 // 00881 #ifdef DEBUG_ATTACH_SILHOUETTE_BMP 00882 if (pSilhouetteInfo != NULL && pSilhouetteBits != NULL) 00883 { 00884 CWxBitmap* wbmpSilhouette = new CWxBitmap(pSilhouetteInfo, pSilhouetteBits); 00885 KernelBitmap* kbmpSilhouette = new KernelBitmap(wbmpSilhouette, TRUE); 00886 00887 SetupFeatherBitmapPalette(kbmpSilhouette); 00888 kbmpSilhouette->AttachDebugCopyToCurrentDocument("Silhouette Bitmap"); 00889 00890 wbmpSilhouette->BMBytes = ((CWxBitmap*)OILBitmap::Default)->BMBytes; 00891 delete kbmpSilhouette; 00892 } 00893 #endif 00894 00895 #ifdef DEBUG_ATTACH_FEATHER_BMP 00896 if (kbmpFeather != NULL) 00897 { 00898 kbmpFeather->AttachDebugCopyToCurrentDocument("Feather Mask Bitmap"); 00899 } 00900 #endif 00901 // 00903 00904 // Silhouette bitmap does not use limited mem manager, so free its DIB ourself. 00905 if (pSilhouetteInfo != NULL && pSilhouetteBits != NULL) 00906 FreeDIB(pSilhouetteInfo, pSilhouetteBits, NULL, FALSE); 00907 00908 return kbmpFeather; 00909 } 00910 00911 00912 00913 /******************************************************************************************** 00914 > FeatherAttrValue:: 00915 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 00916 Created: 03/04/2000 00917 Inputs: ppBmpBits = pointer to a LPBYTE pointer which we should allocate memory for 00918 Outputs: ppBmpBits = monochrome bitmap of the outline of the feathered object(s) 00919 Returns: BitmapInfo structure describing the mono bitmap @ **ppBmpBits 00920 Purpose: Create a monochrome image of the accumulated path, using a white outline so the 00921 resulting image matches the inner contour of the path. The thickness of the line 00922 is determined by the feather width. 00923 NB line width is centred about the path outline. Hence if we require the inner 00924 contour to be featherwidth pixels inside the outline, then need to use a line 00925 width of 2*FeatherSize 00926 NB2 Feathersize is moderated to max 40 pix 00927 SeeAlso: FeatherAttrValue::GetFeatherSize,OffscreenRenderingCompleted,Render 00928 PathAccumulatorPathProcessor 00929 OffscreenRenderer 00930 TechnicalNotes: leverages the offscreen rendering system to get the active renderegion to 00931 render the path into a new bitmap and then restore the renderregion to the 00932 way it was. 00933 00934 I order to avoid DWORD aligning overhead in the convolution code we always 00935 render into bitmaps which are DWORD aligned. This means we need to be careful 00936 when creating a transparency attribute to hold the mask as we must use 00937 the aligned co-ords, not m_OffBB otherwise we will introduce scaling. 00938 NB we do this by drawing more pixels on the right hand border to account 00939 for the alignment. 00940 NB NB NB 00941 Non-technical notes: these notes are out of date so ignore! will fix later. 00942 **********************************************************************************************/ 00943 LPBITMAPINFO FeatherAttrValue::CreateSilhouetteBitmap(GRenderRegion* GRR, 00944 LPBYTE* ppBmpBits, 00945 Path* pOutline) 00946 { 00947 // ERROR3IF(m_pOffscreenBmpInfo == NULL, 00948 // "FeatherAttrValue::CreateSilhouetteBitmap; No offscreen bitmap info."); 00949 00950 // generate a contour of m_GapSize around the path of our linked node, to 00951 // eradicate any small gaps which would otherwise be feathered. 00952 if (pOutline==NULL) 00953 { 00954 if (m_pOuterContour == NULL) 00955 GenerateOuterContour(); 00956 00957 pOutline = m_pOuterContour; 00958 } 00959 00960 // if we couldn't generate our outer contour, or it had no points in it, 00961 // don't try to produce a feather bitmap. 00962 if (pOutline == NULL || pOutline->GetNumCoords() == 0) 00963 { 00964 *ppBmpBits = NULL; 00965 return NULL; 00966 } 00967 00969 // - Work out the appropriate size silhouette bitmap by inflating the invalid 00970 // offscreen rectangle by the blur *radius* (half the feather size). 00971 // - If the blur radius is above the maximum we can do, then we work out *how* 00972 // much bigger it is and render the silhouette bitmap appropriately scaled down. 00973 // - The final feather bitmap will then scale up to fill the offscreen rect, 00974 // making it look like we actually used the requested blur radius. 00975 const double ScaledPixelWidth = GRR->GetScaledPixelWidthDouble(); 00976 const double FeatherMPSize = GetFeatherSize(); 00977 const double FeatherPixelSize = GetFeatherPixelSize(ScaledPixelWidth); 00978 double FeatherScaleFactor = 1; 00979 00980 DocRect drSilhouetteBounds = m_OffBB; 00981 m_drFeatherBB = drSilhouetteBounds; 00982 if (FeatherPixelSize >= MIN_BLUR_DIAMETER) 00983 { 00984 // requested blur diameter = BlurPixDiam pixels. 00985 // actual blur we can do = FeatherPixelSize pixels. 00986 double BlurPixDiam = (ScaledPixelWidth > 0) ? (FeatherMPSize / ScaledPixelWidth) : 0; 00987 if (BlurPixDiam > FeatherPixelSize) 00988 { 00989 FeatherScaleFactor = BlurPixDiam / FeatherPixelSize; 00990 00991 // Scale the silhouette around its centre by the feather scale factor. 00992 // This is so that the rendered silhouette bitmap is has a width of 00993 // at least (2 * FeatherRadius + 1) pixels. 00994 double BoundsSF = (FeatherScaleFactor - 1.0) / 2.0; 00995 UINT32 nWidth = (UINT32)(0.5 + (double)drSilhouetteBounds.Width() * BoundsSF); 00996 UINT32 nHeight = (UINT32)(0.5 + (double)drSilhouetteBounds.Height() * BoundsSF); 00997 drSilhouetteBounds.Inflate(nWidth, nHeight); 00998 m_drFeatherBB = drSilhouetteBounds; 00999 } 01000 01001 // Inflate the silhouette bounds by FeatherRadius pixels around each edge. 01002 // This will shrink down to the correct bounds when blurred. 01003 const UINT32 nBlur = (UINT32)(BlurPixDiam + 0.5); 01004 01005 UINT32 nHiInflate = (nBlur - 1) / 2; 01006 UINT32 nLoInflate = (nBlur - 1) - nHiInflate; 01007 01008 nHiInflate = (UINT32)(ScaledPixelWidth * (double)nHiInflate); 01009 nLoInflate = (UINT32)(ScaledPixelWidth * (double)nLoInflate); 01010 01011 drSilhouetteBounds.hi.x += nHiInflate; 01012 drSilhouetteBounds.hi.y += nHiInflate; 01013 drSilhouetteBounds.lo.x -= nLoInflate; 01014 drSilhouetteBounds.lo.y -= nLoInflate; 01015 01016 // Don't allow further code to try to make a zero pixel silhouette bitmap 01017 if (drSilhouetteBounds.Width()<ScaledPixelWidth || drSilhouetteBounds.Height()<ScaledPixelWidth) 01018 { 01019 *ppBmpBits = NULL; 01020 return NULL; 01021 } 01022 } 01024 01025 // create our offscreen render-region. 01026 ConcurrentRenderer* pRendWrap = NULL; 01027 pRendWrap = GRenderRegionWrapper::GetConcurrentRenderer(GRR, 1.0 / FeatherScaleFactor, 01028 drSilhouetteBounds, 8, FALSE); 01029 if (pRendWrap == NULL) 01030 { 01031 *ppBmpBits = NULL; 01032 return NULL; 01033 } 01034 01035 GRenderRegion* pLocalGRR = NULL; 01036 pLocalGRR = pRendWrap->GetRenderRegion(); 01037 01038 pLocalGRR->GetDrawContext()->SetHintingFlag(FALSE); 01039 01040 // ask the bitmap shadower if it the final feather bitmap will be offset diagonally 01041 // by half a pixel. if this is the case then we must compensate, by rendering 01042 // the silhouette bitmap at a half-pixel offset in the other direction. 01043 if (CBitmapShadow::BlurringWillOffsetBitmap(FeatherPixelSize)) 01044 pLocalGRR->OffsetByHalfPixel(); 01045 01047 // Draw into new RenderRegion which GRenderRegionWrapper has created 01049 pLocalGRR->SaveContext(); 01050 01051 // Initialise our new render-region: 01052 // 1. Render in solid black with solid white line-widths. 01053 // 1a. Line colour now graduates from black -> off-white over 0->2*MIN_BLUR_DIAMETER. 01054 // 2. Line width is half feather size + contour gap size, on either side. 01055 // 3. No arrowheads/dashed lines/fancy join types. 01056 // 4. High quality rendering, so we get anti-aliased lines. 01057 01058 pLocalGRR->SetFillColour(COLOUR_BLACK); 01059 if (FeatherPixelSize < (2*MIN_BLUR_DIAMETER)) 01060 { 01061 double RampValue = FeatherPixelSize / (2*MIN_BLUR_DIAMETER); 01062 ColourValue GreyVal(0.8 * RampValue); 01063 DocColour FeatherGrey(GreyVal, GreyVal, GreyVal); 01064 pLocalGRR->SetLineColour(FeatherGrey); 01065 } 01066 else 01067 pLocalGRR->SetLineColour(COLOUR_WHITE); 01068 01069 pLocalGRR->SetJoinType(RoundJoin); 01070 pLocalGRR->SetStartArrow(SA_NULLARROW); 01071 pLocalGRR->SetEndArrow(SA_NULLARROW); 01072 pLocalGRR->SetDashPattern(SD_SOLID); 01073 01074 MILLIPOINT RequiredLineWidth = (MILLIPOINT)(FeatherMPSize + 2*m_GapSize); 01075 pLocalGRR->SetLineWidth(RequiredLineWidth); 01076 01077 FlatTranspFillAttribute NoFillTransp(TT_NoTranspType); 01078 pLocalGRR->SetTranspFillGeometry(&NoFillTransp, FALSE); 01079 01080 StrokeTranspAttribute NoLineTransp(TT_NoTranspType); 01081 pLocalGRR->SetLineTransp(&NoLineTransp, FALSE); 01082 01083 Quality AntiAliasQuality; 01084 AntiAliasQuality.SetQuality(Quality::QualityMax); 01085 QualityAttribute AntiAliasQualityAttr(AntiAliasQuality); 01086 pLocalGRR->SetQuality(&AntiAliasQualityAttr, FALSE); 01087 01088 // render our contoured silhouette path into the new RR. 01089 pOutline->IsFilled = TRUE; 01090 pOutline->IsStroked = TRUE; 01091 pLocalGRR->DrawPath(pOutline); 01092 pLocalGRR->RestoreContext(); 01093 01095 // Extract bitmap from GRenderRegionWrapper and restore GDraw state 01097 LPBITMAPINFO tmpBI; 01098 pRendWrap->GetBitmapPointers(&tmpBI, ppBmpBits); 01099 pRendWrap->RestorePreviousRendererState(); 01100 01101 return tmpBI; 01102 } 01103 01104 01105 01106 /******************************************************************************************** 01107 > FeatherAttrValue:: 01108 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 01109 Created: 24/01/2000 01110 Purpose: Setup the feather bitmap's palette using the bias/gain profile 01111 SeeAlso: 01112 **********************************************************************************************/ 01113 void FeatherAttrValue::SetupFeatherBitmapPalette(KernelBitmap* pFeatherBMP) 01114 { 01115 LPRGBQUAD pPalette = pFeatherBMP->GetPaletteForBitmap(); 01116 01117 // Using linear palette 01118 // For some reason we have to initialise the palette even though the rendering 01119 // code sets up the palette using the profile which is attached to the bitmap 01120 // transparency attribute which contains the feather bitmap mask. 01121 for (INT32 i = 0; i < 256; i ++) 01122 { 01123 pPalette[i].rgbRed = pPalette[i].rgbBlue = pPalette[i].rgbGreen = (BYTE)i; 01124 pPalette[i].rgbReserved = 0x00; 01125 } 01126 01127 // Mark this bitmap as being greyscale to avoid re-conversion by GetGreyscaleVersion 01128 pFeatherBMP->SetAsGreyscale(); 01129 } 01130 01131 /******************************************************************************************** 01132 > FeatherAttrValue:: 01133 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 01134 Created: 24/01/2000 01135 Purpose: 01136 SeeAlso: 01137 ********************************************************************************************/ 01138 void FeatherAttrValue::CreateBitmapFill(KernelBitmap* pBitmap, DocRect* dr, BitmapFillAttribute* BmpFill) 01139 { 01140 // Bitmap fill is the size of the current offscreen bitmap 01141 DocCoord StartPoint(dr->lo); 01142 DocCoord EndPoint(dr->hi.x,dr->lo.y); 01143 DocCoord EndPoint2(dr->lo.x,dr->hi.y); 01144 DocCoord EndPoint3(dr->hi); 01145 01146 BmpFill->SetStartPoint(&StartPoint); 01147 BmpFill->SetEndPoint(&EndPoint); 01148 BmpFill->SetEndPoint2(&EndPoint2); 01149 BmpFill->SetEndPoint3(&EndPoint3); 01150 BmpFill->GetBitmapRef()->SetBitmap(pBitmap); 01151 } 01152 01153 /******************************************************************************************** 01154 > FeatherAttrValue:: 01155 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 01156 Created: 24/01/2000 01157 Purpose: 01158 SeeAlso: 01159 ********************************************************************************************/ 01160 void FeatherAttrValue::CreateBitmapFillRot90(KernelBitmap* pBitmap, DocRect* dr, BitmapFillAttribute* BmpFill) 01161 { 01162 // Bitmap fill is the size of the current offscreen bitmap 01163 DocCoord StartPoint(dr->hi.x, dr->lo.y); 01164 DocCoord EndPoint(dr->hi); 01165 DocCoord EndPoint2(dr->lo); 01166 DocCoord EndPoint3(dr->lo.x,dr->hi.y); 01167 01168 BmpFill->SetStartPoint(&StartPoint); 01169 BmpFill->SetEndPoint(&EndPoint); 01170 BmpFill->SetEndPoint2(&EndPoint2); 01171 BmpFill->SetEndPoint3(&EndPoint3); 01172 BmpFill->GetBitmapRef()->SetBitmap(pBitmap); 01173 } 01174 01175 void FeatherAttrValue::CreateBitmapTranspFill(KernelBitmap* pFeather, DocRect* dr, BitmapTranspFillAttribute* BmpTranspFill) 01176 { 01177 // Transp fill is same size as viewable part of the bitmap 01178 DocCoord StartPoint(dr->lo); 01179 DocCoord EndPoint(dr->hi.x,dr->lo.y); 01180 DocCoord EndPoint2(dr->lo.x,dr->hi.y); 01181 DocCoord EndPoint3(dr->hi); 01182 01183 BmpTranspFill->SetStartPoint(&StartPoint); 01184 BmpTranspFill->SetEndPoint(&EndPoint); 01185 BmpTranspFill->SetEndPoint2(&EndPoint2); 01186 BmpTranspFill->SetEndPoint3(&EndPoint3); 01187 BmpTranspFill->GetBitmapRef()->SetBitmap(pFeather); 01188 BmpTranspFill->Transp = 0; 01189 BmpTranspFill->EndTransp = 255; 01190 m_Profile.SetIsAFeatherProfile (TRUE); // enable extra processing on the profile 01191 BmpTranspFill->SetProfile(m_Profile); 01192 } 01193 01194 Path* FeatherAttrValue::GetVisibleBoundingPath() 01195 { 01196 DocRect dr = GetOffscreenBoundingRect(); 01197 Path* p = new Path(); 01198 if (p != NULL) 01199 { 01200 p->Initialise(5); 01201 p->CreatePathFromDocRect(&dr); 01202 } 01203 return p; 01204 } 01205 01206 /******************************************************************************************** 01207 > FeatherAttrValue:: 01208 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 01209 Created: 24/01/2000 01210 Inputs: pNode - node to feather (possibly compound node) 01211 size - of feather region (NB millipoint = INT32, pixels = INT32) 01212 - "INT32" rather than "MILLIPOINT" Width used to emphasize that 01213 millipoints are expected but not only measure excepted 01214 01215 type - which measurment used for size 01216 Purpose: Setup feather member variables so that it is created properly on rendering 01217 SeeAlso: OpFeather::Do 01218 ********************************************************************************************/ 01219 BOOL FeatherAttrValue::SetupFeather(Node* pNode, INT32 Width, UnitType type) 01220 { 01221 // Get required feather size in Millipoints, taking current zoom into account 01222 // if width specified in Pixels 01223 MILLIPOINT BlurSize = ConvertMeasurementToMillipointsAtCurrentViewScale(Width,type); 01224 if (BlurSize == -1) 01225 BlurSize = DEFAULT_FEATHERSIZE_MP; 01226 SetFeatherSize(BlurSize); 01227 01228 // Save pointer to node so we can get at it in the rendering code. 01229 SetLinkedNode((NodeRenderableBounded*) pNode); 01230 01231 #ifdef _DEBUG_OFFSCREEN_PIXEL_WIDTH 01232 RenderDebuggingBitmaps(NULL, pNode, 1.0, 32, FALSE); 01233 #endif 01234 01235 return TRUE; 01236 } 01237 01238 /******************************************************************************************** 01239 > FeatherAttrValue:: 01240 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 01241 Created: 24/01/2000 01242 Purpose: 01243 SeeAlso: 01244 ********************************************************************************************/ 01245 BOOL FeatherAttrValue::ChangeFeatherProfile(CProfileBiasGain &biasgain) 01246 { 01247 AFp BiasValue = biasgain.GetBias(); 01248 AFp GainValue = biasgain.GetGain(); 01249 01250 m_Profile.SetBias(BiasValue); 01251 m_Profile.SetGain(GainValue); 01252 01253 return TRUE; 01254 } 01255 01256 /******************************************************************************************** 01257 > FeatherAttrValue:: 01258 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 01259 Created: 24/01/2000 01260 Purpose: 01261 SeeAlso: 01262 ********************************************************************************************/ 01263 BOOL FeatherAttrValue::ChangeFeatherSize(INT32 Width, UnitType type) 01264 { 01265 BOOL res=SetupFeather(GetLinkedNode(), Width, type); 01266 01267 return res; 01268 } 01269 01270 01271 01272 /******************************************************************************************** 01273 01274 > MILLIPOINT FeatherAttrValue::GetFeatherSize() 01275 01276 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 01277 Created: 31/01/2001 01278 01279 Returns: Our feather size, in millipoints. 01280 01281 Purpose: Accessor method for our feather size. 01282 01283 Notes: This value is always capped off to MaxUserFeatherSize millipoints, 01284 to prevent anybody ever using a feather size which we cannot handle. 01285 01286 ********************************************************************************************/ 01287 MILLIPOINT FeatherAttrValue::GetFeatherSize() 01288 { 01289 return (m_FeatherSize > MaxUserFeatherSize) ? MaxUserFeatherSize : m_FeatherSize; 01290 } 01291 01292 01293 01294 /******************************************************************************************** 01295 01296 > MILLIPOINT FeatherAttrValue::SetFeatherSize(MILLIPOINT mpWidth) 01297 01298 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 01299 Created: 31/01/2001 01300 01301 Inputs: Our new feather size, in millipoints. 01302 01303 Returns: The feather size we actually set, taking cap values into account. 01304 01305 Purpose: Mutator method for our feather size. 01306 01307 Notes: This method will not set a value <0 mp or >MaxUserFeatherSize mp, 01308 to prevent us dealing in feather sizes that we cannot handle. 01309 01310 ********************************************************************************************/ 01311 MILLIPOINT FeatherAttrValue::SetFeatherSize(MILLIPOINT mpWidth) 01312 { 01313 m_FeatherSize = mpWidth < 0 ? 0 : 01314 mpWidth > MaxUserFeatherSize ? MaxUserFeatherSize : 01315 mpWidth; 01316 01317 return m_FeatherSize; 01318 } 01319 01320 01321 01322 /******************************************************************************************** 01323 01324 > inline double FeatherAttrValue::GetFeatherPixelSize(double fPixelWidth) 01325 01326 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 01327 Created: 17/08/2000 01328 Inputs: fPixelWidth width of a pixel in millipoints - accepts non-integer values. 01329 01330 Returns: The feather size, in pixels which are fPixelWidth millipoints wide, 01331 capped off to a maximum of (2 * MAX_SHADOW_BLUR) pixels. 01332 01333 Purpose: Return the size of this feather, in pixels of the specified width. 01334 Different from GetFeatherSize(PIXELS) mainly because: 01335 1. we return a double, so eg you can get back a value of 2.5 pix. 01336 2. we're inline. 01337 01338 Notes: inline, as it's small and fast. 01339 01340 ********************************************************************************************/ 01341 inline double FeatherAttrValue::GetFeatherPixelSize(double fPixelWidth) 01342 { 01343 const double MaxFeatherBlurDiameter = 2.0 * MAX_SHADOW_BLUR; 01344 double fFeatherSize = (fPixelWidth <= 0) ? 0 : (double)m_FeatherSize / fPixelWidth; 01345 return (fFeatherSize > MaxFeatherBlurDiameter) ? MaxFeatherBlurDiameter : fFeatherSize; 01346 } 01347 01348 01349 01350 /******************************************************************************************** 01351 > FeatherAttrValue:: 01352 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 01353 Created: 24/01/2000 01354 Purpose: 01355 SeeAlso: 01356 ********************************************************************************************/ 01357 void FeatherAttrValue::SetFeatherProfile(CProfileBiasGain &biasgain) 01358 { 01359 AFp BiasValue = biasgain.GetBias(); 01360 AFp GainValue = biasgain.GetGain(); 01361 01362 m_Profile.SetBias(BiasValue); 01363 m_Profile.SetGain(GainValue); 01364 } 01365 01366 01367 01368 /******************************************************************************************** 01369 01370 > virtual void FeatherAttrValue::SetLinkedNode(NodeRenderableBounded* pNode) 01371 01372 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 01373 Created: 11/10/2000 01374 Purpose: Our outer contour gap size depends on what our linked node is, so we must 01375 recalculate our gap size whenever our linked node is set. 01376 01377 ********************************************************************************************/ 01378 void FeatherAttrValue::SetLinkedNode(NodeRenderableBounded* pNode) 01379 { 01380 m_pLinkedNode = pNode; 01381 01382 if (pNode != NULL) 01383 { 01384 if (IS_A(GetLinkedNode(), NodeGroup) || 01385 IS_A(GetLinkedNode(), NodeMould) || 01386 IS_A(GetLinkedNode(), NodeBlend) || 01387 GetLinkedNode()->IsANodeClipViewController()) 01388 { 01389 m_GapSize = DEFAULT_GAP_TOLERANCE_MP; 01390 } 01391 else 01392 { 01393 m_GapSize = 1; 01394 } 01395 } 01396 } 01397 01398 01399 01400 /******************************************************************************************** 01401 > FeatherAttrValue:: 01402 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 01403 Created: 24/01/2000 01404 Purpose: 01405 SeeAlso: 01406 ********************************************************************************************/ 01407 BOOL FeatherAttrValue::GenerateOuterContour() 01408 { 01409 // fail now if we have no linked node. 01410 if (GetLinkedNode() == NULL) 01411 { 01412 ERROR3("FeatherAttrValue::GenerateOuterContour; Aarrgh!! Where's our linked node?!!"); 01413 return FALSE; 01414 } 01415 01416 // We know we are about to overwrite this value so if it's still set up 01417 // we shuold delete it now to prevent memory leaks 01418 if (m_pOuterContour) 01419 { 01420 delete m_pOuterContour; 01421 m_pOuterContour = NULL; 01422 } 01423 01424 // Get outer contour 01425 // NB m_pOuterContour is a contour which is m_GapSize outside m_pPath's outline 01426 // Outer contour with m_GapSize is used so that small gaps are forced out. This is 01427 // especially desireable when there are a large number of tiny gaps within the object 01428 // we are trying feather (eg the gaps between the 'front windscreen' shape and the 01429 // 'windscreen frame') 01430 01431 m_pOuterContour = new Path; 01432 BOOL fSuccess = 01433 NodeContour::GenerateContourPathForNode(m_pOuterContour, GetLinkedNode(), NULL, 01434 m_GapSize, TRUE, RoundJoin, -1, TRUE, TRUE); 01435 01436 if (!fSuccess) 01437 { 01438 delete m_pOuterContour; 01439 m_pOuterContour = NULL; 01440 } 01441 01442 return fSuccess; 01443 } 01444 01445 /******************************************************************************************** 01446 > FeatherAttrValue:: 01447 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 01448 Created: 3/5/2000 01449 ********************************************************************************************/ 01450 BOOL FeatherAttrValue::CanBeRenderedDirectly() 01451 { 01452 if(!GetLinkedNode()) 01453 return FALSE; 01454 if(GetLinkedNode()->IS_KIND_OF(NodeDocument)) 01455 return FALSE; 01456 if(GetFeatherSize()==0) 01457 return FALSE; 01458 01459 return TRUE; 01460 } 01461 01462 01463 01464 /******************************************************************************************** 01465 01466 > BOOL FeatherAttrValue::RegenerateOuterContourOnNextRedraw(UndoableOperation* pOp = NULL) 01467 01468 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com>; Karim MacDonald 01469 Created: 24/01/2000; 01/03/2001 01470 Inputs: pOp optional ptr to an UndoOp, letting us store undo information. 01471 01472 Returns: TRUE if we were successful, 01473 FALSE otherwise. 01474 01475 Purpose: Clear the cache of our outer-contour path. 01476 01477 See also: AttrFeather::Transform(), AttrFeather::LinkedNodeGeometryHasChanged(). 01478 01479 ********************************************************************************************/ 01480 BOOL FeatherAttrValue::RegenerateOuterContourOnNextRedraw(UndoableOperation* pOp) 01481 { 01482 if (m_pOuterContour != NULL) 01483 { 01484 if (pOp != NULL) 01485 { 01486 // make this undoable 01487 RegenerateFeatherContourAction* pAct = NULL; 01488 if (RegenerateFeatherContourAction::Init(pOp, pOp->GetUndoActionList(), this, m_pOuterContour, &pAct) == AC_FAIL) 01489 { 01490 TRACEALL( _T("FeatherAttrValue::RegenerateOuterContourOnNextRedraw; Could not record undo information.\n")); 01491 return FALSE; 01492 } 01493 } 01494 // don't actually delete the old outer contour 01495 // if it's been saved via the undoable operation. 01496 if (pOp == NULL) 01497 delete m_pOuterContour; 01498 01499 m_pOuterContour = NULL; 01500 } 01501 01502 return TRUE; 01503 } 01504 01505 01506 01508 // 01509 // NodeAttribute classes 01510 // 01512 01513 /******************************************************************************************** 01514 01515 > void AttrFeather::Render( RenderRegion* pRender ) 01516 01517 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> , Karim MacDonald 01518 Created: 24/01/2000 , 21/07/2000 01519 01520 Inputs: pRender the render-region to render into. 01521 01522 Purpose: Render this feather attribute. 01523 We do one or two checks for validity of this attr, and then render its 01524 attribute-value into the RR. 01525 01526 Notes: If you want to customise for different RRs, then override 01527 RenderRegion::SetOffscreen and FeatherAttrValue::OffscreenRenderingCompleted. 01528 01529 Errors: ERROR3 if we have no linked node at the mo'. 01530 01531 See also: FeatherAttrValue::Render(). 01532 01533 ********************************************************************************************/ 01534 void AttrFeather::Render( RenderRegion* pRender ) 01535 { 01536 // no feathering for hit-testing, please. 01537 if (pRender->IsHitDetect()) 01538 return; 01539 01540 // Karim 21/07/2000 01541 // Feathers can render into most render regions. 01542 // If a render region can't deal with feathering, then the attribute will only be 01543 // 'rendered' in the RenderRegion sense - ie plonked on the context stack - and 01544 // no attempt will be made to generate offscreen bitmaps and what-not. 01545 01546 // only bother rendering us if our feather size is non-zero. 01547 if (Value.GetFeatherSize() != 0) 01548 { 01549 // ensure internal pointer is setup for rendering. 01550 if (Value.GetLinkedNode() == NULL) 01551 { 01552 Node* pParent = FindParent(); 01553 if (pParent != NULL && pParent->IsAnObject()) 01554 Value.SetLinkedNode((NodeRenderableBounded*) FindParent()); 01555 01556 else 01557 { 01558 // ERROR3("AttrFeather::Render; No linked node and parent is not an ink-node!"); 01559 return; 01560 } 01561 } 01562 Value.Render(pRender); 01563 } 01564 } 01565 01566 01567 01568 /******************************************************************************************** 01569 > void* AttrFeather::GetDebugDetails(StringBase* Str) 01570 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 01571 Created: 01572 Outputs: Str: String giving debug info about the node 01573 Purpose: For obtaining debug information about the Node 01574 ********************************************************************************************/ 01575 #ifdef _DEBUG 01576 void AttrFeather::GetDebugDetails(StringBase* Str) 01577 { 01578 // Output base class debug info. 01579 NodeRenderable::GetDebugDetails(Str); 01580 01581 // Output our feather size, in millipoints. 01582 MILLIPOINT mp = Value.GetFeatherSize(); 01583 01584 String_256 TempStr; 01585 TempStr._MakeMsg(TEXT("\r\nFeather size (millipoints) #1%ld"), mp); 01586 (*Str) += TempStr; 01587 } 01588 #endif 01589 01590 /******************************************************************************************** 01591 > AttrFeather:: 01592 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 01593 Created: 24/01/2000 01594 Purpose: 01595 SeeAlso: Node::CopyChildren(OpClone); attrmgr::applycurrentattribstonode (opnewregshape) 01596 TODO: Code which uses this to localise attributes must be changed. Inconsistencies 01597 arise if bitmap preserved and subsequently generated from ex-member node only, 01598 and time delays occur if feather bmp regenerated for each member node on 01599 localisation. 01600 ********************************************************************************************/ 01601 Node* AttrFeather::SimpleCopy() 01602 { 01603 AttrFeather* pAttr = new AttrFeather(); 01604 ERRORIF(pAttr==NULL, _R(IDE_NOMORE_MEMORY),NULL); 01605 01606 CopyNodeContents(pAttr); 01607 return pAttr; 01608 } 01609 01610 /******************************************************************************************** 01611 > AttrFeather:: 01612 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 01613 Created: 24/01/2000 01614 Purpose: 01615 ********************************************************************************************/ 01616 void AttrFeather::CopyNodeContents(NodeAttribute *pCopy) 01617 { 01618 NodeAttribute::CopyNodeContents(pCopy); 01619 ((AttrFeather*)pCopy)->Value.SimpleCopy( &Value ); 01620 } 01621 01622 /*********************************************************************************************** 01623 > void AttrFeather::PolyCopyNodeContents(NodeRenderable* pNodeCopy) 01624 01625 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 01626 Created: 18/12/2003 01627 Outputs: - 01628 Purpose: Polymorphically copies the contents of this node to another 01629 Errors: An assertion failure will occur if NodeCopy is NULL 01630 Scope: protected 01631 01632 ***********************************************************************************************/ 01633 01634 void AttrFeather::PolyCopyNodeContents(NodeRenderable* pNodeCopy) 01635 { 01636 ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node"); 01637 ENSURE(IS_A(pNodeCopy, AttrFeather), "PolyCopyNodeContents given wrong dest node type"); 01638 01639 if (IS_A(pNodeCopy, AttrFeather)) 01640 CopyNodeContents((AttrFeather*)pNodeCopy); 01641 } 01642 01643 01644 01645 /******************************************************************************************** 01646 > AttrFeather:: 01647 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 01648 Created: 24/01/2000 01649 Purpose: Closely tied in with the attr optimisation code. The ShouldBeOptimized() 01650 function will only allow a AttrFeather (ie a NodeAttribute) to be factored 01651 out if the contained value's feather size is 0. This will happen when new 01652 nodes are created using a current feather attribute with 0 feather size. 01653 When this occurs we want to let the optimisation code (NormaliseAttributes()) 01654 remove the AttrFeather from the node on insertion into the tree. 01655 NB the check in the optim code is 01656 "if (AttrAleadyAppliedHigherUpTheTree == attrToOptimize)" 01657 so we want to return TRUE if attrToOptimize->Value.feathersize is 0 so that it 01658 gets deleted. 01659 NB As long as the optimisation method is always used to insert nodes into the tree, 01660 and also the order of comparison (ie a==b but not b==a) is preserved, we can always 01661 expect 0 width feathers to be optimised out. 01662 TODOCHECK: Assuming here that == is not required anywhere other than in the attribute 01663 optimisation code. May not be correct behaviour if comparison required in other 01664 circumstance. 01665 ********************************************************************************************/ 01666 INT32 AttrFeather::operator==(const NodeAttribute& NodeAttrib) 01667 { 01668 ERROR3IF(!NodeAttrib.IsAFeatherAttr(), "AttrFeather::operator==; Compared with a non-feather attr."); 01669 AttrFeather *PotentialAttrToOptimize = (AttrFeather*) &NodeAttrib; 01670 01671 return (Value.GetFeatherSize() == PotentialAttrToOptimize->Value.GetFeatherSize()); 01672 } 01673 01674 /******************************************************************************************** 01675 > AttrFeather:: 01676 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 01677 Created: 24/01/2000 01678 Purpose: 01679 SeeAlso: 01680 ********************************************************************************************/ 01681 UINT32 AttrFeather::GetAttrNameID() 01682 { 01683 return (_R(IDS_FEATHER_ATTR_ID)); 01684 } 01685 01686 /******************************************************************************************** 01687 > AttrFeather:: 01688 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 01689 Created: 24/01/2000 01690 Purpose: 01691 SeeAlso: 01692 ********************************************************************************************/ 01693 UINT32 AttrFeather::GetNodeSize() 01694 { 01695 return sizeof(AttrFeather); 01696 } 01697 01698 /******************************************************************************************** 01699 > AttrFeather:: 01700 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 01701 Created: 24/01/2000 01702 Purpose: 01703 SeeAlso: 01704 ********************************************************************************************/ 01705 BOOL AttrFeather::IsAFeatherAttr() const 01706 { 01707 return TRUE; 01708 } 01709 01710 /******************************************************************************************** 01711 > BOOL AttrFeather::DoFeather(Node* pNode, INT32 size = DEFAULT_FEATHERSIZE_MP, UnitType type = MILLIPOINTS) 01712 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 01713 Created: 24/01/2000 01714 Purpose: Setup new FeatherAttrValue to apply feathering or change existing feather size 01715 SeeAlso: OpFeather::Do(),OpChangeFeather::DoWithParam(...) 01716 ********************************************************************************************/ 01717 BOOL AttrFeather::DoFeather(Node* pNode, INT32 size, UnitType type) 01718 { 01719 return Value.SetupFeather(pNode, size, type); 01720 } 01721 01722 /******************************************************************************************** 01723 > AttrFeather:: 01724 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 01725 Created: 24/01/2000 01726 Purpose: 01727 SeeAlso: 01728 ********************************************************************************************/ 01729 BOOL AttrFeather::DoSetProfile(CProfileBiasGain bg) 01730 { 01731 return Value.ChangeFeatherProfile(bg); 01732 } 01733 01734 /******************************************************************************************** 01735 01736 Layering and redundant feather removal 01737 01738 Purpose: Feathers are layered attributes. Feathering individual members in a 01739 group will look visibly different to feathering the entire group (if 01740 any of the children overlap) 01741 Hence once a feather attribute has been inserted in to the tree it must 01742 not be moved around by the optimisation code. 01743 However, we don't want zero size feather attributes to be stuck into the 01744 tree ever. This function determines when an attribute can be optimised 01745 so determined whether we can get rid of rdundant attributes. 01746 Hence we allow optimisation to occur in the case where we have a zero width 01747 feather. 01748 01749 ********************************************************************************************/ 01750 01751 /******************************************************************************************** 01752 > AttrFeather:: 01753 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 01754 Created: 24/01/2000 01755 Purpose: Ensure that this node is not optimised (ie factored out when groups created 01756 or new / cloned nodes inserted into the tree). 01757 01758 Called when :- 01759 1) a new node is inserted into the tree 01760 2) a clone is inserted into the tree 01761 3) a node with feathering applied is being grouped with other nodes 01762 4) when a group with feathering applied is being ungrouped 01763 01764 Feathers should never be optimised. This means that they will always be 01765 inserted into the tree with each new node created, and not factored out. 01766 The default feather after camelot initialises itself (ie on startup) has zero 01767 feather width. To prevent the tree becomming filled with lots of superfluous 01768 0 width feather attrs we have an extra check in AttributeManager::ApplyCurrentAttribsToNode. 01769 01770 SeeAlso: AttributeManager::ApplyCurrentAttribsToNode 01771 ********************************************************************************************/ 01772 BOOL AttrFeather::ShouldBeOptimized() 01773 { 01774 // don't want zero width feathers in the tree 01775 if (Value.GetFeatherSize() == 0) 01776 return TRUE; 01777 01778 return FALSE; 01779 } 01780 01781 /******************************************************************************************** 01782 01783 Feather prevention ;) 01784 01785 Purpose: Feathering is not supported in certain circumstances listed below 01786 Rather than hacking other code to prevent these situations arising 01787 I am using this method to prevent feathers causing damage to other 01788 nodes. 01789 01790 This way feathering can be added simply once the individual 01791 incompatibilities have been resolved 01792 01793 Notes: Attributes aren't always rendered by the standard render loop 01794 (eg DocView::RenderView). Hence this function doesn't catch all cases 01795 where feathers will get rendered, and this test needs to be repeated 01796 in the corresdponding AttrValue::Render() 01797 See RenderRegion::InitDevice() and CCAttrMap::Render() for egs of 01798 where these functions will be skipped. 01799 01800 More Notes: Karim 21/07/2000 01801 I have now annihilated all of the render-region checks - rather than 01802 do checks on the type of render-region, we'll just let the RR's 01803 feather-rendering methods do the job for us. 01804 This makes it a *lot* easier to customise for different RR's ;o) 01805 01806 ********************************************************************************************/ 01807 SubtreeRenderState AttrFeather::RenderSubtree(RenderRegion *pRender, Node** ppNextNode, BOOL bClip) 01808 { 01809 // Can't feather unless attribute is attached to an object (ie something 01810 // with an inkpath) 01811 if (Value.GetLinkedNode() == NULL && FindParent() == NULL) 01812 return SUBTREE_NORENDER; 01813 01814 // don't bother rendering if feather size is zero or we're the default attr. 01815 if (Value.GetFeatherSize() == 0 || Value.IsDefaultFlagSet()) 01816 return SUBTREE_NORENDER; 01817 01818 return SUBTREE_ROOTONLY; 01819 } 01820 01821 01822 /******************************************************************************************** 01823 01824 Dynamic Attribute creation 01825 01826 Purpose: Support dynamic creation of feather attibutes by other complex nodes 01827 (just Blends and Contours so far) 01828 01829 Dynamic attrs are created by CCAttrMap::MakeAppliedAttrMap 01830 which calls NodeRenderableInk::FindAppliedAttributes 01831 01832 However the problem is that some attributes require additional info 01833 inorder to apply themselves to a given path or node. These attributes 01834 are specific to the node that they are attached to, so need an additonal 01835 step to set themselves up after being dynamically created. 01836 01837 Feather attributes need their internal node pointer to be setup. This 01838 pointer is required in order to work out the dimensions of the offscreen 01839 bitmap, to place this bitmap onscreen once it has been created, and to 01840 get the inkpath so that the convolved transparency mask can be created 01841 01842 ********************************************************************************************/ 01843 BOOL AttrFeather::PostDynCreateInit(CCAttrMap* pBlendMap, Path* pInkPath, CCRuntimeClass* CreatorClass) 01844 { 01845 // all defaults will be out by this stage 01846 // blending default to default will return false - so no feather should be in blend attr map 01847 // blending from default to non-def will dyn create a new feather and blend it's state members 01848 // its m_bDefault will be FALSE as it's set in the constructor 01849 ENSURE(!Value.IsDefaultFlagSet(),"How did this attribute get copied from the default attr?"); 01850 01851 if (Value.GetFeatherSize() == 0) 01852 return FALSE; // Won't render and doesn't alloc mem 01853 01854 // Karim 17/08/2000 01855 // Feather attrs usually decide for themselves whether to use a transparency-capable 01856 // bitmap when rendering. However, within contours and blends, we must force them to, 01857 // as they are now detached from the tree, and therefore cannot examine the surroundings 01858 // to make a transparency decision. 01859 Value.SetAlwaysUseTransparency(); 01860 01861 // fix internal node pointer so that we can setup offscreen bitmap 01862 // and create outer contour for generating feather mask 01863 01864 // if we fail (eg out of mem) then put this feather attr into a state so that it won't NeedsToRender() 01865 01866 NodePath* pNodePath = new NodePath(); 01867 if(!pNodePath) 01868 { 01869 return FALSE; // nb don't report errors. simply render without feathering if this fails 01870 } 01871 01872 pNodePath->SetUpPath(pInkPath->GetNumCoords(),12); 01873 pNodePath->InkPath.CopyPathDataFrom(pInkPath); 01874 01875 if(!MakeLineAttributeCompleteForContouring(pNodePath, this, pBlendMap)) 01876 { 01877 // Feather is unrenderable 01878 // Need to de-alloc mem because we will be returning FALSE and 01879 // hence won't be added to the attrmap - therefore no PostDynCreateDeinit 01880 // Set Child pointer to null in case we had partial sucess 01881 // *** Change here if copy attrs from blendmap inside MakeLineAttributeCompleteForContouring 01882 pNodePath->SetChildDangerous(NULL); 01883 delete pNodePath; 01884 return FALSE; 01885 } 01886 01887 Value.SetLinkedNode(pNodePath); 01888 return TRUE; 01889 } 01890 01891 01892 01893 /******************************************************************************************** 01894 01895 > void AttrFeather::PostDynCreateDeInit() 01896 01897 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 01898 Created: Mid-2000 01899 01900 Purpose: Free memory allocated by PostDynCreateInit(..) functions 01901 Errors: No memory needs to be allocated, so cannot fail. 01902 01903 ********************************************************************************************/ 01904 void AttrFeather::PostDynCreateDeInit() 01905 { 01906 if (Value.GetFeatherSize() == 0) 01907 { 01908 ERROR3("Failure to PostDynCreateInit should have removed this attr from the attrmap"); 01909 return; // nothing to de-alloc 01910 } 01911 01912 01913 // Karim 17/08/2000 01914 // This call is for completeness - probably isn't 100% necessary, but 01915 // better safe than sorry. See PostDynCreateInit() above for more info. 01916 Value.UnsetAlwaysUseTransparency(); 01917 01918 // NB this must only be called if you have called PostDynCreateInit(..) 01919 01920 // dealloc the memory that we allocated in order to perform dynamic feathering 01921 // check parent node 01922 Node* pParent = FindParent(); 01923 ENSURE(pParent->FindParent()==NULL && pParent->FindPrevious()==NULL && pParent->FindNext()==NULL,"Parent not created dynamically"); 01924 01925 // delete line attrs which we added 01926 // *** Change here if copy attrs from blendmap inside MakeLineAttributeCompleteForContouring 01927 /* Node* pPrev = FindPrevious(); 01928 if(pPrev) 01929 { 01930 ENSURE(pPrev->FindParent()==pParent,"Deleting dynamic child attrs which we didn't alloc."); 01931 pPrev->SetNextDangerous(NULL); 01932 pParent->CascadeDelete(); 01933 } 01934 */ 01935 pParent->SetChildDangerous(NULL); 01936 delete pParent; 01937 return; 01938 } 01939 01940 01941 01942 /******************************************************************************************** 01943 01944 > BOOL AttrFeather::IsLinkedToThisNode(Node* pNode) 01945 01946 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 01947 Created: Mid-2000 01948 Inputs: pNode ptr to the node to check for linkage. 01949 01950 Returns: TRUE if we're linked to pNode, 01951 FALSE otherwise. 01952 01953 See Also: LinkToGeometry(). 01954 01955 ********************************************************************************************/ 01956 BOOL AttrFeather::IsLinkedToThisNode(Node* pNode) 01957 { 01958 return (Value.GetLinkedNode() == pNode); 01959 } 01960 01961 01962 01963 /******************************************************************************************** 01964 01965 > virtual void AttrFeather::Transform(TransformBase& Trans) 01966 01967 Author: Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com> 01968 Created: 16/10/2000 01969 Inputs: Trans the applied transformation. 01970 Outputs: The feather size of our FeatherAttrValue will scale. 01971 Purpose: Scales the size of the feather as the feathered object is transformed. 01972 01973 ********************************************************************************************/ 01974 void AttrFeather::Transform(TransformBase& Trans) 01975 { 01976 static const FIXED16 One(1.0); 01977 01978 FIXED16 ScaleFactor = Trans.GetScalar(); 01979 if (ScaleFactor != One) 01980 { 01981 // Only transform feather width of the transform allows widths to be affected 01982 // NEW FEATURE? 01983 // if (Trans.TransLines) 01984 // { 01985 MILLIPOINT FeatherSize = Value.GetFeatherSize(); 01986 MILLIPOINT NewSize = INT32(0.5 + fabs(ScaleFactor.MakeDouble() * (double)FeatherSize) ); 01987 FeatherSize = (NewSize == 0) ? 1 : NewSize; 01988 01989 Value.SetFeatherSize(FeatherSize); 01990 // } 01991 } 01992 01993 // Always transform the outer path so that the shape appears correctly during solid drags 01994 Path* pOuterContour = Value.GetOuterContour(); 01995 if (pOuterContour != NULL) 01996 { 01997 Trans.Transform(pOuterContour->GetCoordArray(), pOuterContour->GetNumCoords()); 01998 } 01999 } 02000 02001 02002 02003 /******************************************************************************************** 02004 02005 > BOOL AttrFeather::Blend(BlendAttrParam* pBlendParam) 02006 02007 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 02008 Created: Mid-2000 02009 02010 Inputs: pBlendParam contains the blending info. 02011 Returns: TRUE if success, 02012 FALSE otherwise. 02013 02014 Purpose: Blend us. 02015 02016 Notes: Always returns FALSE if blending from default to default. 02017 NB in this case will never add an attr of this type to the blended attr map 02018 hence PostDynCreateInit will not be called ('cause it doesn't get dyn created!) 02019 02020 Errors: ERROR3 if NULL input param; ENSURE if pBlendParam has no blend-attr. 02021 02022 ********************************************************************************************/ 02023 BOOL AttrFeather::Blend(BlendAttrParam* pBlendParam) 02024 { 02025 // Check entry param isn't NULL 02026 ERROR3IF(pBlendParam == NULL, "NULL entry param"); 02027 if (pBlendParam == NULL) 02028 return FALSE; 02029 02030 BOOL Success = FALSE; 02031 02032 // We have a valid feather to blend, so do it (in the convoluted style copied from other attrs...) 02033 // Get the Value member to blend to the Value member of the other NodeAttribute. 02034 // If it succeeds, ask the blended Value to make a NodeAttribute out of itself. 02035 if (Value.Blend(pBlendParam)) 02036 { 02037 // Get the blended attr val. After this call, the ptr is our reponsibility 02038 // so we have to delete it if it's no longer needed 02039 AttributeValue* pBlendedAttrVal = pBlendParam->GetBlendedAttrVal(); 02040 02041 if (pBlendedAttrVal != NULL) 02042 { 02043 // We have a blended attr val, so ask it to make a NodeAttribute out of itself 02044 // and set the pBlendParam's blended NodeAttribute ptr to it 02045 NodeAttribute* pBlendedAttr = pBlendedAttrVal->MakeNode(); 02046 pBlendParam->SetBlendedAttr(pBlendedAttr); 02047 02048 if (pBlendedAttr != NULL) 02049 { 02050 // We were able to make a blended NodeAttribute 02051 // so delete the blended attr val, and return TRUE 02052 delete pBlendedAttrVal; 02053 Success = TRUE; 02054 } 02055 else 02056 { 02057 // Couldn't make a blended NodeAttribute, so give the blended attr val back 02058 // and return FALSE 02059 pBlendParam->SetBlendedAttrVal(pBlendedAttrVal); 02060 Success = FALSE; 02061 } 02062 } 02063 else 02064 { 02065 ENSURE(FALSE,"Couldn't get blended attr val from BlendAttrParam."); 02066 Success = FALSE; 02067 } 02068 } 02069 02070 return Success; 02071 } 02072 02073 02074 02075 /******************************************************************************************** 02076 > virtual BOOL AttrFeather::PostDynCreateInit( CCAttrMap* pMap, 02077 Node* pNode, 02078 CCRuntimeClass* pCreatorClass) 02079 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 02080 Created: 24/01/2000 02081 Purpose: 02082 SeeAlso: 02083 ********************************************************************************************/ 02084 BOOL AttrFeather::PostDynCreateInit(CCAttrMap* pMap, 02085 Node* pNode, 02086 CCRuntimeClass* pCreatorClass) 02087 { 02088 return TRUE; 02089 } 02090 02091 02092 02093 /******************************************************************************************** 02094 02095 > BOOL AttrFeather::LinkedNodeGeometryHasChanged(UndoableOperation* pOp) 02096 02097 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com>; Karim MacDonald 02098 Created: 27/4/00; 01/03/2001 02099 02100 Inputs: pOp the operation causing our linked node's geometry to change. 02101 Outputs: Our cache of our outer-contour path may be cleared. 02102 Returns: TRUE if successful, 02103 FALSE otherwise. 02104 02105 Purpose: Inform this attribute that the geometry of its linked node may be changing. 02106 02107 Errors: ERROR2 if pOp is NULL - should *never* happen. 02108 02109 See also: Node::AllowOp() + overrides - main place from which this fn is called. 02110 02111 ********************************************************************************************/ 02112 BOOL AttrFeather::LinkedNodeGeometryHasChanged(UndoableOperation* pOp) 02113 { 02114 // DEBUG: 02115 // static UINT32 ctr = 0; 02116 // TRACEUSER( "Karim", _T("%d. LinkedNodeGeometryHasChanged() for 0x%x.\n"), ++ctr, &Value); 02117 02118 ERROR2IF(pOp == NULL, FALSE, 02119 "AttrFeather::LinkedNodeGeometryHasChanged; Should never call with NULL pOp!"); 02120 02121 // Karim 28/02/2000 02122 // If we're undergoing translation, rotation or reflection, then our transform 02123 // method will automatically update our outer-contour. 02124 // In all other cases, we should clear out our outer-contour, 02125 // so it is refreshed at the next render. 02126 // 02127 // The only way to detect whether we're being transformed as above, is to test on the Op. 02128 02129 if (pOp->IS_KIND_OF(TransOperation) 02130 && !pOp->IsKindOf( CC_RUNTIME_CLASS(OpPathNudge) ) 02131 ) 02132 { 02133 // arbitrarily chosen error threshold. 02134 static const double epsilon = 0.000016; 02135 Matrix Mat = ((TransOperation*)pOp)->GetCurrentMatrix(); 02136 if (Mat.IsTranslation() || 02137 Mat.IsReflection() || 02138 Mat.IsRotation(epsilon)) 02139 { 02140 // can only know for sure that we were transformed, 02141 // if our linked node, or one of its parents, is the op's target. 02142 Node* pLinkedNode = Value.GetLinkedNode(); 02143 // Node* pTransNode = ((TransOperation*)pOp)->GetNode(); 02144 // if( pLinkedNode == pTransNode || 02145 // (pTransNode != NULL && pTransNode->IsNodeInSubtree(pLinkedNode)) ) 02146 // return TRUE; 02147 Range* pRange = ((TransOperation*)pOp)->GetTransformRange(); 02148 if (pRange && pRange->Contains(pLinkedNode, TRUE)) 02149 return TRUE; 02150 } 02151 } 02152 02153 return Value.RegenerateOuterContourOnNextRedraw(pOp); 02154 } 02155 02156 /******************************************************************************************** 02157 > virtual void AttrFeather::NewlyCreatedDefaultAttr(NodeDocument* pNode) 02158 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 02159 Created: 27/4/00 02160 Inputs: 02161 Outputs: 02162 Returns: 02163 Purpose: Attributes which are linked to the geometry of the objects which they affect, 02164 may not be able to perform a useful function if attached directly to the 02165 NodeDocument node (ie a default attribute). This function allows a default 02166 attribute of this type to perform an extra initialisation step so that the 02167 Render() function can handle 02168 Errors: 02169 SeeAlso: - 02170 ********************************************************************************************/ 02171 void AttrFeather::NewlyCreatedDefaultAttr(NodeDocument* pNode) 02172 { 02173 Value.SetLinkedNode((NodeRenderableBounded*)pNode); 02174 Value.SetDefault(); 02175 } 02176 02177 /******************************************************************************************** 02178 > AttrFeather:: 02179 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 02180 Created: 9/5/2000 02181 Purpose: connect attribute values internal node pointer 02182 SeeAlso: 02183 ********************************************************************************************/ 02184 BOOL AttrFeather::LinkToGeometry(Node* pContext) 02185 { 02186 Value.SetLinkedNode((NodeRenderableBounded*) pContext); 02187 return TRUE; 02188 } 02189 02190 /******************************************************************************************** 02191 > virtual BOOL AttrFeather::ContainsAttributeValue(AttributeValue* pVal) 02192 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 02193 Created: 7/6/00 02194 Inputs: 02195 Outputs: 02196 Returns: 02197 Purpose: To check if this NodeAttribute contains a the AttributeValue 02198 NB needs to be implemented in a manner specific to the way in which 02199 the derived NodeAttribute class stores the AttributeValue 02200 Errors: 02201 SeeAlso: OffscreenAttrValue::DoesOffscreenBmpRequireTransp 02202 AttrFeather::ContainsAttributeValue 02203 ********************************************************************************************/ 02204 BOOL AttrFeather::ContainsAttributeValue(AttributeValue* pVal) 02205 { 02206 if(!pVal->IS_KIND_OF(FeatherAttrValue)) 02207 { 02208 ENSURE(FALSE,"Strange attr value comparison test requested"); 02209 return FALSE; 02210 } 02211 02212 return (pVal == &Value); 02213 } 02214 02215 /******************************************************************************************** 02216 > AttrFeather:: 02217 Author: Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com> 02218 Created: 24/01/2000 02219 Purpose: 02220 SeeAlso: 02221 ********************************************************************************************/ 02222 02224 // 02225 // Saving and loading 02226 // 02228 BOOL AttrFeather::WritePreChildrenWeb(BaseCamelotFilter* pFilter) 02229 { 02230 ERROR2IF(pFilter == NULL,FALSE,"NULL filter param"); 02231 CXaraFileRecord Rec(TAG_FEATHER,TAG_FEATHER_SIZE); 02232 BOOL ok = TRUE; 02233 02234 MILLIPOINT sz = Value.GetFeatherSize(); 02235 CProfileBiasGain pProfile(Value.GetProfile()); 02236 02237 ok = Rec.Init(); 02238 if (ok) ok = Rec.WriteINT32(sz); 02239 if (ok) ok = Rec.WriteDOUBLE ((double) pProfile.GetBias()); 02240 if (ok) ok = Rec.WriteDOUBLE ((double) pProfile.GetGain()); 02241 if (ok) ok = pFilter->Write(&Rec); 02242 02243 return ok; 02244 } 02245 02246 BOOL AttrFeather::WritePreChildrenNative(BaseCamelotFilter* pFilter) 02247 { 02248 return WritePreChildrenWeb(pFilter); 02249 } 02250 02251 UINT32* FeatherRecordHandler::GetTagList() 02252 { 02253 static UINT32 TagList[] = {TAG_FEATHER,CXFRH_TAG_LIST_END}; 02254 return (UINT32*)&TagList; 02255 } 02256 02257 BOOL FeatherRecordHandler::HandleRecord(CXaraFileRecord* pCXaraFileRecord) 02258 { 02259 ERROR2IF(pCXaraFileRecord == NULL,FALSE,"pCXaraFileRecord is NULL"); 02260 BOOL ok = TRUE; 02261 02262 switch (pCXaraFileRecord->GetTag()) 02263 { 02264 case TAG_FEATHER: 02265 ok = HandleFeatherRecord(pCXaraFileRecord); 02266 break; 02267 02268 default: 02269 ok = FALSE; 02270 ERROR3_PF(("Incorrect tag supplied to HandleRecord. Tag = (%d)\n",pCXaraFileRecord->GetTag())); 02271 break; 02272 } 02273 02274 return ok; 02275 } 02276 02277 BOOL FeatherRecordHandler::HandleFeatherRecord(CXaraFileRecord* pCXaraFileRecord) 02278 { 02279 BOOL ok = TRUE; 02280 02281 MILLIPOINT FeatherSz; 02282 double Bias = 0, Gain = 0; 02283 double* ptrBias = &Bias, *ptrGain = &Gain; 02284 02285 // Read in the feather data 02286 if (ok) ok = pCXaraFileRecord->ReadINT32(&FeatherSz); 02287 if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrBias); 02288 if (ok) ok = pCXaraFileRecord->ReadDOUBLEnoError (ptrGain); 02289 02290 CProfileBiasGain Profile; 02291 02292 if ((ptrBias != NULL) && (ptrGain != NULL)) 02293 { 02294 Profile.SetBias((AFp) Bias); 02295 Profile.SetGain((AFp) Gain); 02296 } 02297 02298 if (ok) 02299 { 02300 AttrFeather* pAttr = new AttrFeather; 02301 if (pAttr != NULL) 02302 { 02303 // Get a ptr to the attr value object 02304 FeatherAttrValue* pValue = (FeatherAttrValue*)&pAttr->Value; 02305 02306 if (pValue != NULL) 02307 { 02308 // Set the feather size 02309 pValue->SetFeatherSize(FeatherSz); 02310 02311 // Set the profile 02312 pValue->SetFeatherProfile(Profile); 02313 02314 if (ok) ok = InsertNode(pAttr); 02315 02316 // Set the m_Node pointer (TODO remove) 02317 if (ok && pBaseCamelotFilter->GetInsertMode()==INSERTMODE_ATTACHTOTREE) 02318 pValue->SetLinkedNode((NodeRenderableBounded*)pAttr->FindParent()); 02319 } 02320 else 02321 ok = FALSE; 02322 } 02323 else 02324 ok = FALSE; 02325 } 02326 02327 return ok; 02328 }