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