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 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 54 GrSegRecord::~GrSegRecord() 55 { 56 clear(); 57 } 58 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 72 void GrSegRecord::clearVectors() 73 { 74 mvGlyphs.clear(); 75 mvCharDxs.clear(); 76 mvChar2BaseGlyph.clear(); 77 mvGlyph2Char.clear(); 78 } 79 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 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