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_vcl.hxx"
30 
31 #ifdef WNT
32 #include <tools/svwin.h>
33 #include <svsys.h>
34 #endif
35 
36 #include <tools/debug.hxx>
37 #include <sallayout.hxx>
38 
39 #include <preextstl.h>
40 #include <graphite/GrClient.h>
41 #include <graphite/Segment.h>
42 #include <postextstl.h>
43 
44 #include <rtl/ustring.hxx>
45 #include <graphite_layout.hxx>
46 #include <graphite_cache.hxx>
47 
48 #include "graphite_textsrc.hxx"
49 
50 GrSegRecord::GrSegRecord(rtl::OUString * rope, TextSourceAdaptor * textSrc, gr::Segment * seg, bool bIsRtl)
51     : m_rope(rope), m_text(textSrc), m_seg(seg), m_nextKey(NULL),
52     m_fontScale(0.0f), mbIsRtl(bIsRtl), m_lockCount(0)
53 {
54     m_pStr = textSrc->getLayoutArgs().mpStr + seg->startCharacter();
55     m_startChar = seg->startCharacter();
56 }
57 
58 GrSegRecord::~GrSegRecord()
59 {
60     clear();
61 }
62 
63 void GrSegRecord::reuse(rtl::OUString * rope, TextSourceAdaptor * textSrc, gr::Segment * seg, bool bIsRtl)
64 {
65     clear();
66     mnWidth = 0;
67     m_rope = rope;
68     m_text = textSrc;
69     m_seg = seg;
70     m_nextKey = NULL;
71     m_pStr = textSrc->getLayoutArgs().mpStr + seg->startCharacter();
72     m_startChar = seg->startCharacter();
73     mbIsRtl = bIsRtl;
74 }
75 
76 void GrSegRecord::clearVectors()
77 {
78     mvGlyphs.clear();
79     mvCharDxs.clear();
80     mvChar2BaseGlyph.clear();
81     mvGlyph2Char.clear();
82 }
83 
84 void GrSegRecord::clear()
85 {
86 #ifdef GR_DEBUG_TEXT
87     if (m_lockCount != 0)
88       OutputDebugString("GrSegRecord locked!");
89 #endif
90     clearVectors();
91     delete m_rope;
92     delete m_seg;
93     delete m_text;
94     m_rope = NULL;
95     m_seg = NULL;
96     m_text = NULL;
97     m_fontScale = 0.0f;
98     m_lockCount = 0;
99 }
100 
101 GrSegRecord * GraphiteSegmentCache::cacheSegment(TextSourceAdaptor * adapter, gr::Segment * seg, bool bIsRtl)
102 {
103     GrSegRecord * record = NULL;
104     // We keep a record of the oldest key and the last key added
105     // when the next key is added, the record for the prevKey's m_nextKey field
106     // is updated to the newest key so that m_oldestKey can be updated to the
107     // next oldest key when the record for m_oldestKey is deleted
108     if (m_segMap.size() > m_nSegCacheSize)
109     {
110       GraphiteSegMap::iterator oldestPair = m_segMap.find(reinterpret_cast<long>(m_oldestKey));
111       // oldest record may no longer exist if a buffer was changed
112       if (oldestPair != m_segMap.end())
113       {
114         record = oldestPair->second;
115         m_segMap.erase(reinterpret_cast<long>(m_oldestKey));
116         GrRMEntry range = m_ropeMap.equal_range((*(record->m_rope)).hashCode());
117         while (range.first != range.second)
118         {
119           if (range.first->second == record)
120           {
121             m_ropeMap.erase(range.first);
122             break;
123           }
124           ++range.first;
125         }
126         m_oldestKey = record->m_nextKey;
127         // record will be reused, so don't delete
128       }
129 	}
130 
131 
132 //    const int seg_char_limit = min(adapter->maLayoutArgs().mnLength,
133 //      adapter->maLayoutArgs().mnEndCharPos
134 //      + GraphiteLayout::EXTRA_CONTEXT_LENGTH);
135 //    if (seg->stopCharacter() - seg->startCharacter() <= 0)
136 //      OutputDebugString("Invalid seg indices\n");
137     rtl::OUString * pRope = new rtl::OUString(adapter->getLayoutArgs().mpStr + seg->startCharacter(),
138        seg->stopCharacter() - seg->startCharacter());
139     if (!pRope) return NULL;
140     bool reuse = false;
141     if (record)
142       record->reuse(pRope, adapter, seg, bIsRtl);
143     else
144       record = new GrSegRecord(pRope, adapter, seg, bIsRtl);
145     if (!record)
146     {
147       delete pRope;
148       return NULL;
149     }
150     GraphiteSegMap::iterator iMap =
151       m_segMap.find(reinterpret_cast<long>(record->m_pStr));
152     if (iMap != m_segMap.end())
153     {
154       // the buffer has changed, so the old cached Segment is useless
155       reuse = true;
156       GrSegRecord * found = iMap->second;
157       // Note: we reuse the old next key to avoid breaking our history
158       // chain. This means it will be prematurely deleted, but this is
159       // unlikely to happen very often.
160       record->m_nextKey = found->m_nextKey;
161       // overwrite the old record
162       m_segMap[reinterpret_cast<long>(record->m_pStr)] = record;
163       // erase the old rope key and save the new one
164       GrRMEntry range = m_ropeMap.equal_range((*(found->m_rope)).hashCode());
165       while (range.first != range.second)
166       {
167         if (range.first->second == found)
168         {
169           m_ropeMap.erase(range.first);
170           break;
171         }
172         ++range.first;
173       }
174       GraphiteRopeMap::value_type mapEntry(record->m_rope->hashCode(), record);
175       m_ropeMap.insert(mapEntry);
176       // remove the old record
177       delete found;
178       record->m_lockCount++;
179       return record;
180     }
181     m_segMap[reinterpret_cast<long>(record->m_pStr)] = record;
182     GraphiteRopeMap::value_type mapEntry((*(record->m_rope)).hashCode(), record);
183     m_ropeMap.insert(mapEntry);
184 
185     if (m_oldestKey == NULL)
186     {
187       m_oldestKey = record->m_pStr;
188       m_prevKey = record->m_pStr;
189     }
190     else if (reuse == false)
191     {
192       DBG_ASSERT(m_segMap.count(reinterpret_cast<long>(m_prevKey)),
193         "Previous key got lost somehow!");
194       m_segMap.find(reinterpret_cast<long>(m_prevKey))
195         ->second->m_nextKey = record->m_pStr;
196       m_prevKey = record->m_pStr;
197     }
198     record->m_lockCount++;
199     return record;
200 }
201