LibreOffice Module canvas (master) 1
pagemanager.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <sal/config.h>
22#include "pagemanager.hxx"
23
24namespace canvas
25{
26 FragmentSharedPtr PageManager::allocateSpace( const ::basegfx::B2ISize& rSize )
27 {
28 // we are asked to find a location for the requested size.
29 // first we try to satisfy the request from the
30 // remaining space in the existing pages.
31 for( const auto& pPage : maPages )
32 {
33 FragmentSharedPtr pFragment( pPage->allocateSpace(rSize) );
34 if(pFragment)
35 {
36 // the page created a new fragment, since we maybe want
37 // to consolidate sparse pages we keep a reference to
38 // the fragment.
39 maFragments.push_back(pFragment);
40 return pFragment;
41 }
42 }
43
44 // otherwise try to create a new page and allocate space there...
45 PageSharedPtr pPage = std::make_shared<Page>(mpRenderModule);
46 if(pPage->isValid())
47 {
48 maPages.push_back(pPage);
49 FragmentSharedPtr pFragment(pPage->allocateSpace(rSize));
50 if (pFragment)
51 maFragments.push_back(pFragment);
52 return pFragment;
53 }
54
55 // the rendermodule failed to create a new page [maybe out
56 // of videomemory], and all other pages could not take
57 // the new request. we decide to create a 'naked' fragment
58 // which will receive its location later.
59 FragmentSharedPtr pFragment = std::make_shared<PageFragment>(rSize);
60 maFragments.push_back(pFragment);
61 return pFragment;
62 }
63
64 void PageManager::free( const FragmentSharedPtr& pFragment )
65 {
66 // erase the reference to the given fragment from our
67 // internal container.
68 FragmentContainer_t::iterator it(
69 std::remove(
70 maFragments.begin(),maFragments.end(),pFragment));
71 maFragments.erase(it,maFragments.end());
72
73 // let the fragment itself know about it...
74 // we need to pass 'this' as argument since the fragment
75 // needs to pass this to the page and can't create
76 // shared_ptr from itself...
77 pFragment->free(pFragment);
78 }
79
81 {
82 if(maPages.empty())
83 return;
84
85 // okay, one last chance is left, we try all available
86 // pages again. maybe some other fragment was deleted
87 // and we can exploit the space.
88 while( !( relocate( pFragment ) ) )
89 {
90 // no way, we need to free up some space...
91 // TODO(F1): this is a heuristic, could
92 // be designed as a policy.
93 auto aEnd( maFragments.cend() );
94 auto aCurrMax( aEnd );
95 sal_uInt32 nCurrMaxArea = 0;
96 for( auto aCurr = maFragments.begin(); aCurr != aEnd; ++aCurr )
97 {
98 if( *aCurr && !( ( *aCurr )->isNaked() ) )
99 {
100 const ::basegfx::B2ISize& rSize( ( *aCurr )->getSize() );
101 sal_uInt32 nArea( rSize.getWidth() * rSize.getHeight() );
102
103 if( nCurrMaxArea < nArea )
104 {
105 aCurrMax = aCurr;
106 nCurrMaxArea = nArea;
107 }
108 }
109 }
110 // this does not erase the candidate,
111 // but makes it 'naked'...
112 if( aCurrMax != aEnd )
113 ( *aCurrMax )->free( *aCurrMax );
114 else
115 break;
116 }
117 }
118
120 {
121 // the fragment passed as argument is assumed to
122 // be naked, that is it is not located on any page.
123 // we try all available pages again, maybe some
124 // other fragment was deleted and we can exploit the space.
125 for( const auto& pPage : maPages )
126 {
127 // if the page at hand takes the fragment, we immediately
128 // call select() to pull the information from the associated
129 // image to the hardware surface.
130 if( pPage->nakedFragment( pFragment ) )
131 {
132 // dirty, since newly allocated.
133 pFragment->select(true);
134 return true;
135 }
136 }
137 return false;
138 }
139
141 {
142 for( const auto& rPagePtr : maPages )
143 rPagePtr->validate();
144 }
145
147 {
148 return { mpRenderModule->getPageSize().getX(),
149 mpRenderModule->getPageSize().getY() };
150 }
151}
152
153/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void nakedFragment(const FragmentSharedPtr &pFragment)
Definition: pagemanager.cxx:80
bool relocate(const FragmentSharedPtr &pFragment)
FragmentSharedPtr allocateSpace(const ::basegfx::B2ISize &rSize)
Definition: pagemanager.cxx:26
FragmentContainer_t maFragments
Definition: pagemanager.hxx:60
::basegfx::B2ISize getPageSize() const
std::vector< PageSharedPtr > maPages
Definition: pagemanager.hxx:64
std::shared_ptr< canvas::IRenderModule > mpRenderModule
Definition: pagemanager.hxx:55
void free(const FragmentSharedPtr &pFragment)
Definition: pagemanager.cxx:64
std::shared_ptr< PageFragment > FragmentSharedPtr
Definition: page.hxx:35
std::shared_ptr< Page > PageSharedPtr
Definition: page.hxx:64