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