зеркало из https://github.com/mozilla/gecko-dev.git
Bug 410728. Detect words that start with a combining mark, and don't cache them. r=vlad
This commit is contained in:
Родитель
cf11c1a40c
Коммит
03fe06e0ca
|
@ -44,7 +44,21 @@
|
|||
/**
|
||||
* Cache individual "words" (strings delimited by white-space or white-space-like
|
||||
* characters that don't involve kerning or ligatures) in textruns.
|
||||
*/
|
||||
*
|
||||
* The characters treated as word boundaries are defined by IsWordBoundary
|
||||
* below. The characters are: space, NBSP, and all the characters
|
||||
* defined by gfxFontGroup::IsInvalidChar. The latter are all converted
|
||||
* to invisible missing glyphs in this code. Thus, this class ensures
|
||||
* that none of those invalid characters are ever passed to platform
|
||||
* textrun implementations.
|
||||
*
|
||||
* Some platforms support marks combining with spaces to form clusters.
|
||||
* In such cases we treat "before the space" as a word boundary but
|
||||
* "after the space" is not a word boundary; words with a leading space
|
||||
* are kept out of the cache. Also, words at the start of text, which start
|
||||
* with combining marks that would combine with a space if there was one,
|
||||
* are also kept out of the cache.
|
||||
*/
|
||||
class TextRunWordCache {
|
||||
public:
|
||||
TextRunWordCache() {
|
||||
|
@ -159,7 +173,7 @@ protected:
|
|||
PRUint32 aStart, PRUint32 aEnd, PRUint32 aHash,
|
||||
nsTArray<DeferredWord>* aDeferredWords);
|
||||
void FinishTextRun(gfxTextRun *aTextRun, gfxTextRun *aNewRun,
|
||||
gfxContext *aContext,
|
||||
const gfxFontGroup::Parameters *aParams,
|
||||
const nsTArray<DeferredWord>& aDeferredWords,
|
||||
PRBool aSuccessful);
|
||||
void RemoveWord(gfxTextRun *aTextRun, PRUint32 aStart,
|
||||
|
@ -307,7 +321,7 @@ TextRunWordCache::LookupWord(gfxTextRun *aTextRun, gfxFont *aFirstFont,
|
|||
*/
|
||||
void
|
||||
TextRunWordCache::FinishTextRun(gfxTextRun *aTextRun, gfxTextRun *aNewRun,
|
||||
gfxContext *aContext,
|
||||
const gfxFontGroup::Parameters *aParams,
|
||||
const nsTArray<DeferredWord>& aDeferredWords,
|
||||
PRBool aSuccessful)
|
||||
{
|
||||
|
@ -322,23 +336,37 @@ TextRunWordCache::FinishTextRun(gfxTextRun *aTextRun, gfxTextRun *aNewRun,
|
|||
gfxTextRun *source = word->mSourceTextRun;
|
||||
if (!source) {
|
||||
source = aNewRun;
|
||||
// we created a cache entry for this word based on the assumption
|
||||
}
|
||||
// If the word starts inside a cluster we don't want this word
|
||||
// in the cache, so we'll remove the associated cache entry
|
||||
PRBool wordStartsInsideCluster =
|
||||
!source->IsClusterStart(word->mSourceOffset);
|
||||
if (source == aNewRun) {
|
||||
// We created a cache entry for this word based on the assumption
|
||||
// that the word matches GetFontAt(0). If this assumption is false,
|
||||
// we need to remove that cache entry and replace it with an entry
|
||||
// keyed off the fontgroup.
|
||||
if (!aSuccessful ||
|
||||
GetWordFontOrGroup(aNewRun, word->mSourceOffset, word->mLength) != font) {
|
||||
PRBool rekeyWithFontGroup =
|
||||
GetWordFontOrGroup(aNewRun, word->mSourceOffset, word->mLength) != font;
|
||||
if (!aSuccessful || wordStartsInsideCluster || rekeyWithFontGroup) {
|
||||
// We need to remove the current placeholder cache entry
|
||||
CacheHashKey key(aTextRun, font, word->mDestOffset, word->mLength,
|
||||
word->mHash);
|
||||
NS_ASSERTION(mCache.GetEntry(key),
|
||||
"This entry should have been added previously!");
|
||||
mCache.RemoveEntry(key);
|
||||
#ifdef DEBUG
|
||||
--aTextRun->mCachedWords;
|
||||
#endif
|
||||
PR_LOG(gWordCacheLog, PR_LOG_DEBUG, ("%p(%d-%d,%d): removed using font", aTextRun, word->mDestOffset, word->mLength, word->mHash));
|
||||
|
||||
if (aSuccessful) {
|
||||
if (aSuccessful && !wordStartsInsideCluster) {
|
||||
key.mFontOrGroup = fontGroup;
|
||||
CacheHashEntry *groupEntry = mCache.PutEntry(key);
|
||||
if (groupEntry) {
|
||||
#ifdef DEBUG
|
||||
++aTextRun->mCachedWords;
|
||||
#endif
|
||||
PR_LOG(gWordCacheLog, PR_LOG_DEBUG, ("%p(%d-%d,%d): added using fontgroup", aTextRun, word->mDestOffset, word->mLength, word->mHash));
|
||||
groupEntry->mTextRun = aTextRun;
|
||||
groupEntry->mWordOffset = word->mDestOffset;
|
||||
|
@ -353,9 +381,38 @@ TextRunWordCache::FinishTextRun(gfxTextRun *aTextRun, gfxTextRun *aNewRun,
|
|||
// Copy the word. If the source is aNewRun, then
|
||||
// allow CopyGlyphDataFrom to steal the internal data of
|
||||
// aNewRun since that's only temporary anyway.
|
||||
aTextRun->CopyGlyphDataFrom(source,
|
||||
word->mSourceOffset, word->mLength, word->mDestOffset,
|
||||
source == aNewRun);
|
||||
PRUint32 sourceOffset = word->mSourceOffset;
|
||||
PRUint32 destOffset = word->mDestOffset;
|
||||
PRUint32 length = word->mLength;
|
||||
nsAutoPtr<gfxTextRun> tmpTextRun;
|
||||
PRBool stealData = source == aNewRun;
|
||||
if (wordStartsInsideCluster) {
|
||||
NS_ASSERTION(sourceOffset > 0, "How can the first character be inside a cluster?");
|
||||
if (destOffset > 0 && IsBoundarySpace(aTextRun->GetChar(destOffset - 1))) {
|
||||
// We should copy over data for the preceding space
|
||||
// as well. The glyphs have probably been attached
|
||||
// to that character.
|
||||
--sourceOffset;
|
||||
--destOffset;
|
||||
++length;
|
||||
} else {
|
||||
// URK! This case sucks! We have combining marks
|
||||
// at the start of the text. We had to prepend a space
|
||||
// just so we could detect these are combining marks
|
||||
// (so we can keep this "word" out of the cache).
|
||||
// But now the data in aNewRun is no use to us. We
|
||||
// need to find out what the platform would do
|
||||
// if the marks were at the start of the text.
|
||||
tmpTextRun = aNewRun->GetFontGroup()->MakeTextRun(
|
||||
aTextRun->GetTextUnicode(), length, aParams,
|
||||
aNewRun->GetFlags());
|
||||
source = tmpTextRun;
|
||||
sourceOffset = 0;
|
||||
stealData = PR_TRUE;
|
||||
}
|
||||
}
|
||||
aTextRun->CopyGlyphDataFrom(source, sourceOffset, length,
|
||||
destOffset, stealData);
|
||||
// Fill in additional spaces
|
||||
PRUint32 endCharIndex;
|
||||
if (i + 1 < aDeferredWords.Length()) {
|
||||
|
@ -367,7 +424,7 @@ TextRunWordCache::FinishTextRun(gfxTextRun *aTextRun, gfxTextRun *aNewRun,
|
|||
for (charIndex = word->mDestOffset + word->mLength;
|
||||
charIndex < endCharIndex; ++charIndex) {
|
||||
if (IsBoundarySpace(aTextRun->GetChar(charIndex))) {
|
||||
aTextRun->SetSpaceGlyph(font, aContext, charIndex);
|
||||
aTextRun->SetSpaceGlyph(font, aParams->mContext, charIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -425,9 +482,9 @@ TextRunWordCache::MakeTextRun(const PRUnichar *aText, PRUint32 aLength,
|
|||
PRBool hit = LookupWord(textRun, font, wordStart, i, hash,
|
||||
deferredWords.Length() == 0 ? nsnull : &deferredWords);
|
||||
if (!hit) {
|
||||
if (tempString.Length() > 0) {
|
||||
tempString.AppendElement(' ');
|
||||
}
|
||||
// Always put a space before the word so we can detect
|
||||
// combining characters at the start of a word
|
||||
tempString.AppendElement(' ');
|
||||
PRUint32 offset = tempString.Length();
|
||||
PRUint32 length = i - wordStart;
|
||||
PRUnichar *chars = tempString.AppendElements(length);
|
||||
|
@ -467,7 +524,7 @@ TextRunWordCache::MakeTextRun(const PRUnichar *aText, PRUint32 aLength,
|
|||
newRun = aFontGroup->MakeTextRun(tempString.Elements(), tempString.Length(),
|
||||
¶ms, aFlags | gfxTextRunFactory::TEXT_IS_PERSISTENT);
|
||||
|
||||
FinishTextRun(textRun, newRun, aParams->mContext, deferredWords, newRun != nsnull);
|
||||
FinishTextRun(textRun, newRun, aParams, deferredWords, newRun != nsnull);
|
||||
return textRun.forget();
|
||||
}
|
||||
|
||||
|
@ -550,7 +607,7 @@ TextRunWordCache::MakeTextRun(const PRUint8 *aText, PRUint32 aLength,
|
|||
newRun = aFontGroup->MakeTextRun(tempString.Elements(), tempString.Length(),
|
||||
¶ms, aFlags | gfxTextRunFactory::TEXT_IS_PERSISTENT);
|
||||
|
||||
FinishTextRun(textRun, newRun, aParams->mContext, deferredWords, newRun != nsnull);
|
||||
FinishTextRun(textRun, newRun, aParams, deferredWords, newRun != nsnull);
|
||||
return textRun.forget();
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче