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