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