1464702f4SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3464702f4SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4464702f4SAndrew Rist * or more contributor license agreements. See the NOTICE file 5464702f4SAndrew Rist * distributed with this work for additional information 6464702f4SAndrew Rist * regarding copyright ownership. The ASF licenses this file 7464702f4SAndrew Rist * to you under the Apache License, Version 2.0 (the 8464702f4SAndrew Rist * "License"); you may not use this file except in compliance 9464702f4SAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 11464702f4SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 13464702f4SAndrew Rist * Unless required by applicable law or agreed to in writing, 14464702f4SAndrew Rist * software distributed under the License is distributed on an 15464702f4SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16464702f4SAndrew Rist * KIND, either express or implied. See the License for the 17464702f4SAndrew Rist * specific language governing permissions and limitations 18464702f4SAndrew Rist * under the License. 19cdf0e10cSrcweir * 20464702f4SAndrew Rist *************************************************************/ 21464702f4SAndrew Rist 22464702f4SAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 25cdf0e10cSrcweir #include "precompiled_drawinglayer.hxx" 26cdf0e10cSrcweir 27cdf0e10cSrcweir #include <vclhelperbufferdevice.hxx> 28cdf0e10cSrcweir #include <basegfx/range/b2drange.hxx> 29cdf0e10cSrcweir #include <vcl/bitmapex.hxx> 30cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx> 31cdf0e10cSrcweir #include <tools/stream.hxx> 32ce37d08fSArmin Le Grand #include <vcl/timer.hxx> 33ce37d08fSArmin Le Grand #include <comphelper/broadcasthelper.hxx> 34*33a1c393SArmin Le Grand #include <vcl/lazydelete.hxx> 35ce37d08fSArmin Le Grand 36ce37d08fSArmin Le Grand ////////////////////////////////////////////////////////////////////////////// 37ce37d08fSArmin Le Grand // buffered VDev usage 38ce37d08fSArmin Le Grand 39ce37d08fSArmin Le Grand namespace 40ce37d08fSArmin Le Grand { 41ce37d08fSArmin Le Grand typedef ::std::vector< VirtualDevice* > aBuffers; 42ce37d08fSArmin Le Grand 43ce37d08fSArmin Le Grand class VDevBuffer : public Timer, protected comphelper::OBaseMutex 44ce37d08fSArmin Le Grand { 45ce37d08fSArmin Le Grand private: 46ce37d08fSArmin Le Grand aBuffers maBuffers; 47ce37d08fSArmin Le Grand 48ce37d08fSArmin Le Grand public: 49ce37d08fSArmin Le Grand VDevBuffer(); 50ce37d08fSArmin Le Grand virtual ~VDevBuffer(); 51ce37d08fSArmin Le Grand 52ce37d08fSArmin Le Grand VirtualDevice* alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, bool bMono); 53ce37d08fSArmin Le Grand void free(VirtualDevice& rDevice); 54ce37d08fSArmin Le Grand 55ce37d08fSArmin Le Grand // Timer virtuals 56ce37d08fSArmin Le Grand virtual void Timeout(); 57ce37d08fSArmin Le Grand }; 58ce37d08fSArmin Le Grand 59ce37d08fSArmin Le Grand VDevBuffer::VDevBuffer() 60ce37d08fSArmin Le Grand : Timer(), 61ce37d08fSArmin Le Grand maBuffers() 62ce37d08fSArmin Le Grand { 63ce37d08fSArmin Le Grand SetTimeout(10L * 1000L); // ten seconds 64ce37d08fSArmin Le Grand } 65ce37d08fSArmin Le Grand 66ce37d08fSArmin Le Grand VDevBuffer::~VDevBuffer() 67ce37d08fSArmin Le Grand { 68ce37d08fSArmin Le Grand ::osl::MutexGuard aGuard(m_aMutex); 69ce37d08fSArmin Le Grand Stop(); 70ce37d08fSArmin Le Grand 71ce37d08fSArmin Le Grand while(!maBuffers.empty()) 72ce37d08fSArmin Le Grand { 73ce37d08fSArmin Le Grand delete *(maBuffers.end() - 1); 74ce37d08fSArmin Le Grand maBuffers.pop_back(); 75ce37d08fSArmin Le Grand } 76ce37d08fSArmin Le Grand } 77ce37d08fSArmin Le Grand 78ce37d08fSArmin Le Grand VirtualDevice* VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, bool bMono) 79ce37d08fSArmin Le Grand { 80ce37d08fSArmin Le Grand ::osl::MutexGuard aGuard(m_aMutex); 81ce37d08fSArmin Le Grand VirtualDevice* pRetval = 0; 82ce37d08fSArmin Le Grand 83ce37d08fSArmin Le Grand if(!maBuffers.empty()) 84ce37d08fSArmin Le Grand { 85ce37d08fSArmin Le Grand bool bOkay(false); 86ce37d08fSArmin Le Grand aBuffers::iterator aFound(maBuffers.end()); 87ce37d08fSArmin Le Grand 88ce37d08fSArmin Le Grand for(aBuffers::iterator a(maBuffers.begin()); a != maBuffers.end(); a++) 89ce37d08fSArmin Le Grand { 90ce37d08fSArmin Le Grand OSL_ENSURE(*a, "Empty pointer in VDevBuffer (!)"); 91ce37d08fSArmin Le Grand 92ce37d08fSArmin Le Grand if((bMono && 1 == (*a)->GetBitCount()) || (!bMono && (*a)->GetBitCount() > 1)) 93ce37d08fSArmin Le Grand { 94ce37d08fSArmin Le Grand // candidate is valid due to bit depth 95ce37d08fSArmin Le Grand if(aFound != maBuffers.end()) 96ce37d08fSArmin Le Grand { 97ce37d08fSArmin Le Grand // already found 98ce37d08fSArmin Le Grand if(bOkay) 99ce37d08fSArmin Le Grand { 100ce37d08fSArmin Le Grand // found is valid 101ce37d08fSArmin Le Grand const bool bCandidateOkay((*a)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*a)->GetOutputHeightPixel() >= rSizePixel.getHeight()); 102ce37d08fSArmin Le Grand 103ce37d08fSArmin Le Grand if(bCandidateOkay) 104ce37d08fSArmin Le Grand { 105ce37d08fSArmin Le Grand // found and candidate are valid 106ce37d08fSArmin Le Grand const sal_uLong aSquare((*aFound)->GetOutputWidthPixel() * (*aFound)->GetOutputHeightPixel()); 107ce37d08fSArmin Le Grand const sal_uLong aCandidateSquare((*a)->GetOutputWidthPixel() * (*a)->GetOutputHeightPixel()); 108ce37d08fSArmin Le Grand 109ce37d08fSArmin Le Grand if(aCandidateSquare < aSquare) 110ce37d08fSArmin Le Grand { 111ce37d08fSArmin Le Grand // candidate is valid and smaller, use it 112ce37d08fSArmin Le Grand aFound = a; 113ce37d08fSArmin Le Grand } 114ce37d08fSArmin Le Grand } 115ce37d08fSArmin Le Grand else 116ce37d08fSArmin Le Grand { 117ce37d08fSArmin Le Grand // found is valid, candidate is not. Keep found 118ce37d08fSArmin Le Grand } 119ce37d08fSArmin Le Grand } 120ce37d08fSArmin Le Grand else 121ce37d08fSArmin Le Grand { 122ce37d08fSArmin Le Grand // found is invalid, use candidate 123ce37d08fSArmin Le Grand aFound = a; 124ce37d08fSArmin Le Grand bOkay = (*aFound)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*aFound)->GetOutputHeightPixel() >= rSizePixel.getHeight(); 125ce37d08fSArmin Le Grand } 126ce37d08fSArmin Le Grand } 127ce37d08fSArmin Le Grand else 128ce37d08fSArmin Le Grand { 129ce37d08fSArmin Le Grand // none yet, use candidate 130ce37d08fSArmin Le Grand aFound = a; 131ce37d08fSArmin Le Grand bOkay = (*aFound)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*aFound)->GetOutputHeightPixel() >= rSizePixel.getHeight(); 132ce37d08fSArmin Le Grand } 133ce37d08fSArmin Le Grand } 134ce37d08fSArmin Le Grand } 135ce37d08fSArmin Le Grand 136ce37d08fSArmin Le Grand if(aFound != maBuffers.end()) 137ce37d08fSArmin Le Grand { 138ce37d08fSArmin Le Grand pRetval = *aFound; 139ce37d08fSArmin Le Grand maBuffers.erase(aFound); 140ce37d08fSArmin Le Grand 141ce37d08fSArmin Le Grand if(bOkay) 142ce37d08fSArmin Le Grand { 143ce37d08fSArmin Le Grand if(bClear) 144ce37d08fSArmin Le Grand { 145ce37d08fSArmin Le Grand pRetval->Erase(Rectangle(0, 0, rSizePixel.getWidth(), rSizePixel.getHeight())); 146ce37d08fSArmin Le Grand } 147ce37d08fSArmin Le Grand } 148ce37d08fSArmin Le Grand else 149ce37d08fSArmin Le Grand { 150ce37d08fSArmin Le Grand pRetval->SetOutputSizePixel(rSizePixel, bClear); 151ce37d08fSArmin Le Grand } 152ce37d08fSArmin Le Grand } 153ce37d08fSArmin Le Grand } 154ce37d08fSArmin Le Grand 155ce37d08fSArmin Le Grand // no success yet, create new buffer 156ce37d08fSArmin Le Grand if(!pRetval) 157ce37d08fSArmin Le Grand { 158ce37d08fSArmin Le Grand pRetval = (bMono) ? new VirtualDevice(rOutDev, 1) : new VirtualDevice(rOutDev); 159ce37d08fSArmin Le Grand pRetval->SetOutputSizePixel(rSizePixel, bClear); 160ce37d08fSArmin Le Grand } 161ce37d08fSArmin Le Grand else 162ce37d08fSArmin Le Grand { 163ce37d08fSArmin Le Grand // reused, reset some values 164ce37d08fSArmin Le Grand pRetval->SetMapMode(); 165ce37d08fSArmin Le Grand } 166ce37d08fSArmin Le Grand 167ce37d08fSArmin Le Grand return pRetval; 168ce37d08fSArmin Le Grand } 169ce37d08fSArmin Le Grand 170ce37d08fSArmin Le Grand void VDevBuffer::free(VirtualDevice& rDevice) 171ce37d08fSArmin Le Grand { 172ce37d08fSArmin Le Grand ::osl::MutexGuard aGuard(m_aMutex); 173ce37d08fSArmin Le Grand maBuffers.push_back(&rDevice); 174ce37d08fSArmin Le Grand Start(); 175ce37d08fSArmin Le Grand } 176ce37d08fSArmin Le Grand 177ce37d08fSArmin Le Grand void VDevBuffer::Timeout() 178ce37d08fSArmin Le Grand { 179ce37d08fSArmin Le Grand ::osl::MutexGuard aGuard(m_aMutex); 180ce37d08fSArmin Le Grand 181ce37d08fSArmin Le Grand while(!maBuffers.empty()) 182ce37d08fSArmin Le Grand { 183ce37d08fSArmin Le Grand delete *(maBuffers.end() - 1); 184ce37d08fSArmin Le Grand maBuffers.pop_back(); 185ce37d08fSArmin Le Grand } 186ce37d08fSArmin Le Grand } 187ce37d08fSArmin Le Grand } 188cdf0e10cSrcweir 189cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 190cdf0e10cSrcweir // support for rendering Bitmap and BitmapEx contents 191cdf0e10cSrcweir 192cdf0e10cSrcweir namespace drawinglayer 193cdf0e10cSrcweir { 194ce37d08fSArmin Le Grand // static global VDev buffer for the VclProcessor2D's (VclMetafileProcessor2D and VclPixelProcessor2D) 195*33a1c393SArmin Le Grand VDevBuffer& getVDevBuffer() 196*33a1c393SArmin Le Grand { 197*33a1c393SArmin Le Grand // secure global instance with Vcl's safe desroyer of external (seen by 198*33a1c393SArmin Le Grand // library base) stuff, the remembered VDevs need to be deleted before 199*33a1c393SArmin Le Grand // Vcl's deinit 200*33a1c393SArmin Le Grand static vcl::DeleteOnDeinit< VDevBuffer > aVDevBuffer(new VDevBuffer()); 201*33a1c393SArmin Le Grand return *aVDevBuffer.get(); 202*33a1c393SArmin Le Grand } 203ce37d08fSArmin Le Grand 204cdf0e10cSrcweir impBufferDevice::impBufferDevice( 205cdf0e10cSrcweir OutputDevice& rOutDev, 206cdf0e10cSrcweir const basegfx::B2DRange& rRange, 207cdf0e10cSrcweir bool bAddOffsetToMapping) 208cdf0e10cSrcweir : mrOutDev(rOutDev), 209ce37d08fSArmin Le Grand mpContent(0), 210ce37d08fSArmin Le Grand mpMask(0), 211ce37d08fSArmin Le Grand mpAlpha(0) 212cdf0e10cSrcweir { 213cdf0e10cSrcweir basegfx::B2DRange aRangePixel(rRange); 214ce37d08fSArmin Le Grand aRangePixel.transform(mrOutDev.GetViewTransformation()); 215cdf0e10cSrcweir const Rectangle aRectPixel( 216cdf0e10cSrcweir (sal_Int32)floor(aRangePixel.getMinX()), (sal_Int32)floor(aRangePixel.getMinY()), 217cdf0e10cSrcweir (sal_Int32)ceil(aRangePixel.getMaxX()), (sal_Int32)ceil(aRangePixel.getMaxY())); 218cdf0e10cSrcweir const Point aEmptyPoint; 219ce37d08fSArmin Le Grand maDestPixel = Rectangle(aEmptyPoint, mrOutDev.GetOutputSizePixel()); 220cdf0e10cSrcweir maDestPixel.Intersection(aRectPixel); 221cdf0e10cSrcweir 222cdf0e10cSrcweir if(isVisible()) 223cdf0e10cSrcweir { 224*33a1c393SArmin Le Grand mpContent = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), false, false); 225cdf0e10cSrcweir 226cdf0e10cSrcweir // #i93485# assert when copying from window to VDev is used 227ce37d08fSArmin Le Grand OSL_ENSURE(mrOutDev.GetOutDevType() != OUTDEV_WINDOW, 228cdf0e10cSrcweir "impBufferDevice render helper: Copying from Window to VDev, this should be avoided (!)"); 229cdf0e10cSrcweir 230ce37d08fSArmin Le Grand const bool bWasEnabledSrc(mrOutDev.IsMapModeEnabled()); 231ce37d08fSArmin Le Grand mrOutDev.EnableMapMode(false); 232ce37d08fSArmin Le Grand mpContent->DrawOutDev(aEmptyPoint, maDestPixel.GetSize(), maDestPixel.TopLeft(), maDestPixel.GetSize(), mrOutDev); 233ce37d08fSArmin Le Grand mrOutDev.EnableMapMode(bWasEnabledSrc); 234cdf0e10cSrcweir 235ce37d08fSArmin Le Grand MapMode aNewMapMode(mrOutDev.GetMapMode()); 236cdf0e10cSrcweir 237cdf0e10cSrcweir if(bAddOffsetToMapping) 238cdf0e10cSrcweir { 239ce37d08fSArmin Le Grand const Point aLogicTopLeft(mrOutDev.PixelToLogic(maDestPixel.TopLeft())); 240cdf0e10cSrcweir aNewMapMode.SetOrigin(Point(-aLogicTopLeft.X(), -aLogicTopLeft.Y())); 241cdf0e10cSrcweir } 242cdf0e10cSrcweir 243ce37d08fSArmin Le Grand mpContent->SetMapMode(aNewMapMode); 244cdf0e10cSrcweir 245cdf0e10cSrcweir // copy AA flag for new target 246ce37d08fSArmin Le Grand mpContent->SetAntialiasing(mrOutDev.GetAntialiasing()); 247cdf0e10cSrcweir } 248cdf0e10cSrcweir } 249cdf0e10cSrcweir 250cdf0e10cSrcweir impBufferDevice::~impBufferDevice() 251cdf0e10cSrcweir { 252ce37d08fSArmin Le Grand if(mpContent) 253ce37d08fSArmin Le Grand { 254*33a1c393SArmin Le Grand getVDevBuffer().free(*mpContent); 255ce37d08fSArmin Le Grand } 256ce37d08fSArmin Le Grand 257ce37d08fSArmin Le Grand if(mpMask) 258ce37d08fSArmin Le Grand { 259*33a1c393SArmin Le Grand getVDevBuffer().free(*mpMask); 260ce37d08fSArmin Le Grand } 261ce37d08fSArmin Le Grand 262ce37d08fSArmin Le Grand if(mpAlpha) 263ce37d08fSArmin Le Grand { 264*33a1c393SArmin Le Grand getVDevBuffer().free(*mpAlpha); 265ce37d08fSArmin Le Grand } 266cdf0e10cSrcweir } 267cdf0e10cSrcweir 268cdf0e10cSrcweir void impBufferDevice::paint(double fTrans) 269cdf0e10cSrcweir { 270ce37d08fSArmin Le Grand if(isVisible()) 271ce37d08fSArmin Le Grand { 272cdf0e10cSrcweir const Point aEmptyPoint; 273ce37d08fSArmin Le Grand const Size aSizePixel(maDestPixel.GetSize()); 274cdf0e10cSrcweir const bool bWasEnabledDst(mrOutDev.IsMapModeEnabled()); 275cdf0e10cSrcweir static bool bDoSaveForVisualControl(false); 276cdf0e10cSrcweir 277cdf0e10cSrcweir mrOutDev.EnableMapMode(false); 278ce37d08fSArmin Le Grand mpContent->EnableMapMode(false); 279ce37d08fSArmin Le Grand Bitmap aContent(mpContent->GetBitmap(aEmptyPoint, aSizePixel)); 280cdf0e10cSrcweir 281cdf0e10cSrcweir if(bDoSaveForVisualControl) 282cdf0e10cSrcweir { 283cdf0e10cSrcweir SvFileStream aNew((const String&)String(ByteString( "c:\\content.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC); 284cdf0e10cSrcweir aNew << aContent; 285cdf0e10cSrcweir } 286cdf0e10cSrcweir 287cdf0e10cSrcweir if(mpAlpha) 288cdf0e10cSrcweir { 289cdf0e10cSrcweir mpAlpha->EnableMapMode(false); 290cdf0e10cSrcweir const AlphaMask aAlphaMask(mpAlpha->GetBitmap(aEmptyPoint, aSizePixel)); 291cdf0e10cSrcweir 292cdf0e10cSrcweir if(bDoSaveForVisualControl) 293cdf0e10cSrcweir { 294cdf0e10cSrcweir SvFileStream aNew((const String&)String(ByteString( "c:\\transparence.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC); 295cdf0e10cSrcweir aNew << aAlphaMask.GetBitmap(); 296cdf0e10cSrcweir } 297cdf0e10cSrcweir 298cdf0e10cSrcweir mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask)); 299cdf0e10cSrcweir } 300cdf0e10cSrcweir else if(mpMask) 301cdf0e10cSrcweir { 302cdf0e10cSrcweir mpMask->EnableMapMode(false); 303cdf0e10cSrcweir const Bitmap aMask(mpMask->GetBitmap(aEmptyPoint, aSizePixel)); 304cdf0e10cSrcweir 305cdf0e10cSrcweir if(bDoSaveForVisualControl) 306cdf0e10cSrcweir { 307cdf0e10cSrcweir SvFileStream aNew((const String&)String(ByteString( "c:\\mask.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC); 308cdf0e10cSrcweir aNew << aMask; 309cdf0e10cSrcweir } 310cdf0e10cSrcweir 311cdf0e10cSrcweir mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aMask)); 312cdf0e10cSrcweir } 313cdf0e10cSrcweir else if(0.0 != fTrans) 314cdf0e10cSrcweir { 315cdf0e10cSrcweir sal_uInt8 nMaskValue((sal_uInt8)basegfx::fround(fTrans * 255.0)); 316cdf0e10cSrcweir const AlphaMask aAlphaMask(aSizePixel, &nMaskValue); 317cdf0e10cSrcweir mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask)); 318cdf0e10cSrcweir } 319cdf0e10cSrcweir else 320cdf0e10cSrcweir { 321cdf0e10cSrcweir mrOutDev.DrawBitmap(maDestPixel.TopLeft(), aContent); 322cdf0e10cSrcweir } 323cdf0e10cSrcweir 324cdf0e10cSrcweir mrOutDev.EnableMapMode(bWasEnabledDst); 325cdf0e10cSrcweir } 326ce37d08fSArmin Le Grand } 327ce37d08fSArmin Le Grand 328ce37d08fSArmin Le Grand VirtualDevice& impBufferDevice::getContent() 329ce37d08fSArmin Le Grand { 330ce37d08fSArmin Le Grand OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)"); 331ce37d08fSArmin Le Grand return *mpContent; 332ce37d08fSArmin Le Grand } 333cdf0e10cSrcweir 334cdf0e10cSrcweir VirtualDevice& impBufferDevice::getMask() 335cdf0e10cSrcweir { 336ce37d08fSArmin Le Grand OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)"); 337cdf0e10cSrcweir if(!mpMask) 338cdf0e10cSrcweir { 339*33a1c393SArmin Le Grand mpMask = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, true); 340ce37d08fSArmin Le Grand mpMask->SetMapMode(mpContent->GetMapMode()); 341cdf0e10cSrcweir 342cdf0e10cSrcweir // do NOT copy AA flag for mask! 343cdf0e10cSrcweir } 344cdf0e10cSrcweir 345cdf0e10cSrcweir return *mpMask; 346cdf0e10cSrcweir } 347cdf0e10cSrcweir 348cdf0e10cSrcweir VirtualDevice& impBufferDevice::getTransparence() 349cdf0e10cSrcweir { 350ce37d08fSArmin Le Grand OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)"); 351cdf0e10cSrcweir if(!mpAlpha) 352cdf0e10cSrcweir { 353*33a1c393SArmin Le Grand mpAlpha = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, false); 354ce37d08fSArmin Le Grand mpAlpha->SetMapMode(mpContent->GetMapMode()); 355cdf0e10cSrcweir 356cdf0e10cSrcweir // copy AA flag for new target; masking needs to be smooth 357ce37d08fSArmin Le Grand mpAlpha->SetAntialiasing(mpContent->GetAntialiasing()); 358cdf0e10cSrcweir } 359cdf0e10cSrcweir 360cdf0e10cSrcweir return *mpAlpha; 361cdf0e10cSrcweir } 362cdf0e10cSrcweir } // end of namespace drawinglayer 363cdf0e10cSrcweir 364cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 365cdf0e10cSrcweir // eof 366