/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_canvas.hxx" #include #include "pagemanager.hxx" namespace canvas { ////////////////////////////////////////////////////////////////////////////////// // PageManager ////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// // PageManager::allocateSpace ////////////////////////////////////////////////////////////////////////////////// FragmentSharedPtr PageManager::allocateSpace( const ::basegfx::B2ISize& rSize ) { // we are asked to find a location for the requested size. // first we try to satisfy the request from the // remaining space in the existing pages. const PageContainer_t::iterator aEnd(maPages.end()); PageContainer_t::iterator it(maPages.begin()); while(it != aEnd) { FragmentSharedPtr pFragment((*it)->allocateSpace(rSize)); if(pFragment) { // the page created a new fragment, since we maybe want // to consolidate sparse pages we keep a reference to // the fragment. maFragments.push_back(pFragment); return pFragment; } ++it; } // otherwise try to create a new page and allocate space there... PageSharedPtr pPage(new Page(mpRenderModule)); if(pPage->isValid()) { maPages.push_back(pPage); FragmentSharedPtr pFragment(pPage->allocateSpace(rSize)); if (pFragment) maFragments.push_back(pFragment); return pFragment; } // the rendermodule failed to create a new page [maybe out // of videomemory], and all other pages could not take // the new request. we decide to create a 'naked' fragment // which will receive its location later. FragmentSharedPtr pFragment(new PageFragment(rSize)); maFragments.push_back(pFragment); return pFragment; } ////////////////////////////////////////////////////////////////////////////////// // PageManager::free ////////////////////////////////////////////////////////////////////////////////// void PageManager::free( const FragmentSharedPtr& pFragment ) { // erase the reference to the given fragment from our // internal container. FragmentContainer_t::iterator it( std::remove( maFragments.begin(),maFragments.end(),pFragment)); maFragments.erase(it,maFragments.end()); // let the fragment itself know about it... // we need to pass 'this' as argument since the fragment // needs to pass this to the page and can't create // shared_ptr from itself... pFragment->free(pFragment); } ////////////////////////////////////////////////////////////////////////////////// // PageManager::nakedFragment ////////////////////////////////////////////////////////////////////////////////// void PageManager::nakedFragment( const FragmentSharedPtr& pFragment ) { if(maPages.empty()) return; // okay, one last chance is left, we try all available // pages again. maybe some other fragment was deleted // and we can exploit the space. while(!(relocate(pFragment))) { // no way, we need to free up some space... // TODO(F1): this is a heuristic, could // be designed as a policy. const FragmentContainer_t::const_iterator aEnd(maFragments.end()); FragmentContainer_t::const_iterator candidate(maFragments.begin()); while(candidate != aEnd) { if(*candidate && !((*candidate)->isNaked())) break; ++candidate; } if (candidate != aEnd) { const ::basegfx::B2ISize& rSize((*candidate)->getSize()); sal_uInt32 nMaxArea(rSize.getX()*rSize.getY()); FragmentContainer_t::const_iterator it(candidate); while(it != aEnd) { if (*it && !((*it)->isNaked())) { const ::basegfx::B2ISize& rCandidateSize((*it)->getSize()); const sal_uInt32 nArea(rCandidateSize.getX()*rCandidateSize.getY()); if(nArea > nMaxArea) { candidate=it; nMaxArea=nArea; } } ++it; } // this does not erase the candidate, // but makes it 'naked'... (*candidate)->free(*candidate); } else break; } } ////////////////////////////////////////////////////////////////////////////////// // PageManager::relocate ////////////////////////////////////////////////////////////////////////////////// bool PageManager::relocate( const FragmentSharedPtr& pFragment ) { // the fragment passed as argument is assumed to // be naked, that is it is not located on any page. // we try all available pages again, maybe some // other fragment was deleted and we can exploit the space. const PageContainer_t::iterator aEnd(maPages.end()); PageContainer_t::iterator it(maPages.begin()); while(it != aEnd) { // if the page at hand takes the fragment, we immediately // call select() to pull the information from the associated // image to the hardware surface. if((*it)->nakedFragment(pFragment)) { // dirty, since newly allocated. pFragment->select(true); return true; } ++it; } return false; } ////////////////////////////////////////////////////////////////////////////////// // PageManager::validatePages ////////////////////////////////////////////////////////////////////////////////// void PageManager::validatePages() { ::std::for_each( maPages.begin(), maPages.end(), ::boost::mem_fn(&Page::validate)); } ////////////////////////////////////////////////////////////////////////////////// // PageManager::getPageSize ////////////////////////////////////////////////////////////////////////////////// ::basegfx::B2ISize PageManager::getPageSize() const { return mpRenderModule->getPageSize(); } ////////////////////////////////////////////////////////////////////////////////// // PageManager::getRenderModule ////////////////////////////////////////////////////////////////////////////////// canvas::IRenderModuleSharedPtr PageManager::getRenderModule() const { return mpRenderModule; } }