xref: /trunk/main/canvas/source/tools/pagemanager.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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