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