/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_vcl.hxx" #ifdef WNT #include #include #endif #include #include #include #include #include #include #include #include #include #include "graphite_textsrc.hxx" GrSegRecord::GrSegRecord(rtl::OUString * rope, TextSourceAdaptor * textSrc, gr::Segment * seg, bool bIsRtl) : m_rope(rope), m_text(textSrc), m_seg(seg), m_nextKey(NULL), m_fontScale(0.0f), mbIsRtl(bIsRtl), m_lockCount(0) { m_pStr = textSrc->getLayoutArgs().mpStr + seg->startCharacter(); m_startChar = seg->startCharacter(); } GrSegRecord::~GrSegRecord() { clear(); } void GrSegRecord::reuse(rtl::OUString * rope, TextSourceAdaptor * textSrc, gr::Segment * seg, bool bIsRtl) { clear(); mnWidth = 0; m_rope = rope; m_text = textSrc; m_seg = seg; m_nextKey = NULL; m_pStr = textSrc->getLayoutArgs().mpStr + seg->startCharacter(); m_startChar = seg->startCharacter(); mbIsRtl = bIsRtl; } void GrSegRecord::clearVectors() { mvGlyphs.clear(); mvCharDxs.clear(); mvChar2BaseGlyph.clear(); mvGlyph2Char.clear(); } void GrSegRecord::clear() { #ifdef GR_DEBUG_TEXT if (m_lockCount != 0) OutputDebugString("GrSegRecord locked!"); #endif clearVectors(); delete m_rope; delete m_seg; delete m_text; m_rope = NULL; m_seg = NULL; m_text = NULL; m_fontScale = 0.0f; m_lockCount = 0; } GrSegRecord * GraphiteSegmentCache::cacheSegment(TextSourceAdaptor * adapter, gr::Segment * seg, bool bIsRtl) { GrSegRecord * record = NULL; // We keep a record of the oldest key and the last key added // when the next key is added, the record for the prevKey's m_nextKey field // is updated to the newest key so that m_oldestKey can be updated to the // next oldest key when the record for m_oldestKey is deleted if (m_segMap.size() > m_nSegCacheSize) { GraphiteSegMap::iterator oldestPair = m_segMap.find(reinterpret_cast(m_oldestKey)); // oldest record may no longer exist if a buffer was changed if (oldestPair != m_segMap.end()) { record = oldestPair->second; m_segMap.erase(reinterpret_cast(m_oldestKey)); GrRMEntry range = m_ropeMap.equal_range((*(record->m_rope)).hashCode()); while (range.first != range.second) { if (range.first->second == record) { m_ropeMap.erase(range.first); break; } ++range.first; } m_oldestKey = record->m_nextKey; // record will be reused, so don't delete } } // const int seg_char_limit = min(adapter->maLayoutArgs().mnLength, // adapter->maLayoutArgs().mnEndCharPos // + GraphiteLayout::EXTRA_CONTEXT_LENGTH); // if (seg->stopCharacter() - seg->startCharacter() <= 0) // OutputDebugString("Invalid seg indices\n"); rtl::OUString * pRope = new rtl::OUString(adapter->getLayoutArgs().mpStr + seg->startCharacter(), seg->stopCharacter() - seg->startCharacter()); if (!pRope) return NULL; bool reuse = false; if (record) record->reuse(pRope, adapter, seg, bIsRtl); else record = new GrSegRecord(pRope, adapter, seg, bIsRtl); if (!record) { delete pRope; return NULL; } GraphiteSegMap::iterator iMap = m_segMap.find(reinterpret_cast(record->m_pStr)); if (iMap != m_segMap.end()) { // the buffer has changed, so the old cached Segment is useless reuse = true; GrSegRecord * found = iMap->second; // Note: we reuse the old next key to avoid breaking our history // chain. This means it will be prematurely deleted, but this is // unlikely to happen very often. record->m_nextKey = found->m_nextKey; // overwrite the old record m_segMap[reinterpret_cast(record->m_pStr)] = record; // erase the old rope key and save the new one GrRMEntry range = m_ropeMap.equal_range((*(found->m_rope)).hashCode()); while (range.first != range.second) { if (range.first->second == found) { m_ropeMap.erase(range.first); break; } ++range.first; } GraphiteRopeMap::value_type mapEntry(record->m_rope->hashCode(), record); m_ropeMap.insert(mapEntry); // remove the old record delete found; record->m_lockCount++; return record; } m_segMap[reinterpret_cast(record->m_pStr)] = record; GraphiteRopeMap::value_type mapEntry((*(record->m_rope)).hashCode(), record); m_ropeMap.insert(mapEntry); if (m_oldestKey == NULL) { m_oldestKey = record->m_pStr; m_prevKey = record->m_pStr; } else if (reuse == false) { DBG_ASSERT(m_segMap.count(reinterpret_cast(m_prevKey)), "Previous key got lost somehow!"); m_segMap.find(reinterpret_cast(m_prevKey)) ->second->m_nextKey = record->m_pStr; m_prevKey = record->m_pStr; } record->m_lockCount++; return record; }