1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_canvas.hxx" 26 27 #include <boost/bind.hpp> 28 #include "pagemanager.hxx" 29 30 namespace canvas 31 { 32 33 ////////////////////////////////////////////////////////////////////////////////// 34 // PageManager 35 ////////////////////////////////////////////////////////////////////////////////// 36 37 ////////////////////////////////////////////////////////////////////////////////// 38 // PageManager::allocateSpace 39 ////////////////////////////////////////////////////////////////////////////////// 40 allocateSpace(const::basegfx::B2ISize & rSize)41 FragmentSharedPtr PageManager::allocateSpace( const ::basegfx::B2ISize& rSize ) 42 { 43 // we are asked to find a location for the requested size. 44 // first we try to satisfy the request from the 45 // remaining space in the existing pages. 46 const PageContainer_t::iterator aEnd(maPages.end()); 47 PageContainer_t::iterator it(maPages.begin()); 48 while(it != aEnd) 49 { 50 FragmentSharedPtr pFragment((*it)->allocateSpace(rSize)); 51 if(pFragment) 52 { 53 // the page created a new fragment, since we maybe want 54 // to consolidate sparse pages we keep a reference to 55 // the fragment. 56 maFragments.push_back(pFragment); 57 return pFragment; 58 } 59 60 ++it; 61 } 62 63 // otherwise try to create a new page and allocate space there... 64 PageSharedPtr pPage(new Page(mpRenderModule)); 65 if(pPage->isValid()) 66 { 67 maPages.push_back(pPage); 68 FragmentSharedPtr pFragment(pPage->allocateSpace(rSize)); 69 if (pFragment) 70 maFragments.push_back(pFragment); 71 return pFragment; 72 } 73 74 // the rendermodule failed to create a new page [maybe out 75 // of videomemory], and all other pages could not take 76 // the new request. we decide to create a 'naked' fragment 77 // which will receive its location later. 78 FragmentSharedPtr pFragment(new PageFragment(rSize)); 79 maFragments.push_back(pFragment); 80 return pFragment; 81 } 82 83 ////////////////////////////////////////////////////////////////////////////////// 84 // PageManager::free 85 ////////////////////////////////////////////////////////////////////////////////// 86 free(const FragmentSharedPtr & pFragment)87 void PageManager::free( const FragmentSharedPtr& pFragment ) 88 { 89 // erase the reference to the given fragment from our 90 // internal container. 91 FragmentContainer_t::iterator it( 92 std::remove( 93 maFragments.begin(),maFragments.end(),pFragment)); 94 maFragments.erase(it,maFragments.end()); 95 96 // let the fragment itself know about it... 97 // we need to pass 'this' as argument since the fragment 98 // needs to pass this to the page and can't create 99 // shared_ptr from itself... 100 pFragment->free(pFragment); 101 } 102 103 ////////////////////////////////////////////////////////////////////////////////// 104 // PageManager::nakedFragment 105 ////////////////////////////////////////////////////////////////////////////////// 106 nakedFragment(const FragmentSharedPtr & pFragment)107 void PageManager::nakedFragment( const FragmentSharedPtr& pFragment ) 108 { 109 if(maPages.empty()) 110 return; 111 112 // okay, one last chance is left, we try all available 113 // pages again. maybe some other fragment was deleted 114 // and we can exploit the space. 115 while(!(relocate(pFragment))) 116 { 117 // no way, we need to free up some space... 118 // TODO(F1): this is a heuristic, could 119 // be designed as a policy. 120 const FragmentContainer_t::const_iterator aEnd(maFragments.end()); 121 FragmentContainer_t::const_iterator candidate(maFragments.begin()); 122 while(candidate != aEnd) 123 { 124 if(*candidate && !((*candidate)->isNaked())) 125 break; 126 ++candidate; 127 } 128 129 if (candidate != aEnd) 130 { 131 const ::basegfx::B2ISize& rSize((*candidate)->getSize()); 132 sal_uInt32 nMaxArea(rSize.getX()*rSize.getY()); 133 134 FragmentContainer_t::const_iterator it(candidate); 135 while(it != aEnd) 136 { 137 if (*it && !((*it)->isNaked())) 138 { 139 const ::basegfx::B2ISize& rCandidateSize((*it)->getSize()); 140 const sal_uInt32 nArea(rCandidateSize.getX()*rCandidateSize.getY()); 141 if(nArea > nMaxArea) 142 { 143 candidate=it; 144 nMaxArea=nArea; 145 } 146 } 147 148 ++it; 149 } 150 151 // this does not erase the candidate, 152 // but makes it 'naked'... 153 (*candidate)->free(*candidate); 154 } 155 else 156 break; 157 } 158 } 159 160 ////////////////////////////////////////////////////////////////////////////////// 161 // PageManager::relocate 162 ////////////////////////////////////////////////////////////////////////////////// 163 relocate(const FragmentSharedPtr & pFragment)164 bool PageManager::relocate( const FragmentSharedPtr& pFragment ) 165 { 166 // the fragment passed as argument is assumed to 167 // be naked, that is it is not located on any page. 168 // we try all available pages again, maybe some 169 // other fragment was deleted and we can exploit the space. 170 const PageContainer_t::iterator aEnd(maPages.end()); 171 PageContainer_t::iterator it(maPages.begin()); 172 while(it != aEnd) 173 { 174 // if the page at hand takes the fragment, we immediatelly 175 // call select() to pull the information from the associated 176 // image to the hardware surface. 177 if((*it)->nakedFragment(pFragment)) 178 { 179 // dirty, since newly allocated. 180 pFragment->select(true); 181 return true; 182 } 183 184 ++it; 185 } 186 187 return false; 188 } 189 190 ////////////////////////////////////////////////////////////////////////////////// 191 // PageManager::validatePages 192 ////////////////////////////////////////////////////////////////////////////////// 193 validatePages()194 void PageManager::validatePages() 195 { 196 ::std::for_each( maPages.begin(), 197 maPages.end(), 198 ::boost::mem_fn(&Page::validate)); 199 } 200 201 ////////////////////////////////////////////////////////////////////////////////// 202 // PageManager::getPageSize 203 ////////////////////////////////////////////////////////////////////////////////// 204 getPageSize() const205 ::basegfx::B2ISize PageManager::getPageSize() const 206 { 207 return mpRenderModule->getPageSize(); 208 } 209 210 ////////////////////////////////////////////////////////////////////////////////// 211 // PageManager::getRenderModule 212 ////////////////////////////////////////////////////////////////////////////////// 213 getRenderModule() const214 canvas::IRenderModuleSharedPtr PageManager::getRenderModule() const 215 { 216 return mpRenderModule; 217 } 218 } 219