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