зеркало из https://github.com/mozilla/pjs.git
Bug 372629. Draw missing-glyph boxes with the Unicode character inscribed in hex. r=pavlov
This commit is contained in:
Родитель
e564057cca
Коммит
c89d0c6fcc
|
@ -774,6 +774,9 @@ public:
|
|||
PRBool IsComplex(PRUint32 aTag) const { return (mValue & (FLAG_IS_SIMPLE_GLYPH|TAG_MASK)) == aTag; }
|
||||
PRBool IsMissing() const { return IsComplex(TAG_MISSING); }
|
||||
PRBool IsComplexCluster() const { return IsComplex(TAG_COMPLEX_CLUSTER); }
|
||||
PRBool IsComplexOrMissing() const {
|
||||
return IsComplex(TAG_COMPLEX_CLUSTER) || IsComplex(TAG_MISSING);
|
||||
}
|
||||
PRBool IsLigatureContinuation() const { return IsComplex(TAG_LIGATURE_CONTINUATION); }
|
||||
PRBool IsClusterContinuation() const { return IsComplex(TAG_CLUSTER_CONTINUATION); }
|
||||
PRBool IsLowSurrogate() const { return IsComplex(TAG_LOW_SURROGATE); }
|
||||
|
@ -821,6 +824,8 @@ public:
|
|||
/** This is true for the last DetailedGlyph in the array. This lets
|
||||
* us track the length of the array. */
|
||||
PRUint32 mIsLastGlyph:1;
|
||||
/** The glyphID if this is a ComplexCluster, or the Unicode character
|
||||
* if this is a Missing glyph */
|
||||
PRUint32 mGlyphID:31;
|
||||
// The advance, x-offset and y-offset of the glyph, in appunits
|
||||
PRInt32 mAdvance;
|
||||
|
@ -866,6 +871,8 @@ public:
|
|||
/**
|
||||
* We've found a run of text that should use a particular font. Call this
|
||||
* only during initialization when font substitution has been computed.
|
||||
* Call it before setting up the glyphs for the characters in this run;
|
||||
* SetMissingGlyph requires that the correct glyphrun be installed.
|
||||
*/
|
||||
nsresult AddGlyphRun(gfxFont *aFont, PRUint32 aStartCharIndex);
|
||||
void ResetGlyphRuns() { mGlyphRuns.Clear(); }
|
||||
|
@ -892,6 +899,7 @@ public:
|
|||
*/
|
||||
void SetDetailedGlyphs(PRUint32 aCharIndex, const DetailedGlyph *aGlyphs,
|
||||
PRUint32 aNumGlyphs);
|
||||
void SetMissingGlyph(PRUint32 aCharIndex, PRUnichar aChar);
|
||||
|
||||
// API for access to the raw glyph data, needed by gfxFont::Draw
|
||||
// and gfxFont::GetBoundingBox
|
||||
|
@ -911,6 +919,8 @@ public:
|
|||
private:
|
||||
// **** general helpers ****
|
||||
|
||||
// Allocate aCount DetailedGlyphs for the given index
|
||||
DetailedGlyph *AllocateDetailedGlyphs(PRUint32 aCharIndex, PRUint32 aCount);
|
||||
// Returns the index of the GlyphRun containing the given offset.
|
||||
// Returns mGlyphRuns.Length() when aOffset is mCharacterCount.
|
||||
PRUint32 FindFirstGlyphRunContaining(PRUint32 aOffset);
|
||||
|
|
|
@ -28,6 +28,7 @@ CPPSRCS = \
|
|||
gfxFont.cpp \
|
||||
gfxFontTest.cpp \
|
||||
gfxMatrix.cpp \
|
||||
gfxFontMissingGlyphs.cpp \
|
||||
gfxPattern.cpp \
|
||||
gfxPlatform.cpp \
|
||||
gfxRect.cpp \
|
||||
|
|
|
@ -518,7 +518,8 @@ GetAdvanceAppUnits(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount,
|
|||
static void
|
||||
SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount,
|
||||
Fixed *aBaselineDeltas, PRUint32 aAppUnitsPerDevUnit,
|
||||
gfxTextRun *aRun)
|
||||
gfxTextRun *aRun, const PRPackedBool *aUnmatched,
|
||||
const PRUnichar *aString)
|
||||
{
|
||||
NS_ASSERTION(aGlyphCount > 0, "Must set at least one glyph");
|
||||
PRUint32 firstOffset = aGlyphs[0].originalOffset;
|
||||
|
@ -527,12 +528,16 @@ SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount,
|
|||
PRUint32 regularGlyphCount = 0;
|
||||
ATSLayoutRecord *displayGlyph = nsnull;
|
||||
PRBool inOrder = PR_TRUE;
|
||||
PRBool allMatched = PR_TRUE;
|
||||
|
||||
for (i = 0; i < aGlyphCount; ++i) {
|
||||
ATSLayoutRecord *glyph = &aGlyphs[i];
|
||||
PRUint32 offset = glyph->originalOffset;
|
||||
firstOffset = PR_MIN(firstOffset, offset);
|
||||
lastOffset = PR_MAX(lastOffset, offset);
|
||||
if (aUnmatched && aUnmatched[offset/2]) {
|
||||
allMatched = PR_FALSE;
|
||||
}
|
||||
if (glyph->glyphID != ATSUI_SPECIAL_GLYPH_ID) {
|
||||
++regularGlyphCount;
|
||||
displayGlyph = glyph;
|
||||
|
@ -542,6 +547,14 @@ SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount,
|
|||
}
|
||||
}
|
||||
|
||||
if (!allMatched) {
|
||||
for (i = firstOffset; i <= lastOffset; ++i) {
|
||||
PRUint32 index = i/2;
|
||||
aRun->SetMissingGlyph(index, aString[index]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
PRUint32 offset;
|
||||
for (offset = firstOffset + 2; offset <= lastOffset; offset += 2) {
|
||||
|
@ -572,7 +585,7 @@ SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount,
|
|||
ATSLayoutRecord *advanceStart = aGlyphs;
|
||||
for (i = 0; i < aGlyphCount; ++i) {
|
||||
ATSLayoutRecord *glyph = &aGlyphs[i];
|
||||
if (glyph->glyphID != ATSUI_SPECIAL_GLYPH_ID || regularGlyphCount == 0) {
|
||||
if (glyph->glyphID != ATSUI_SPECIAL_GLYPH_ID) {
|
||||
if (detailedGlyphs.Length() > 0) {
|
||||
detailedGlyphs[detailedGlyphs.Length() - 1].mAdvance =
|
||||
GetAdvanceAppUnits(advanceStart, glyph - advanceStart, aAppUnitsPerDevUnit);
|
||||
|
@ -598,8 +611,6 @@ SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount,
|
|||
detailedGlyphs[detailedGlyphs.Length() - 1].mIsLastGlyph = PR_TRUE;
|
||||
detailedGlyphs[detailedGlyphs.Length() - 1].mAdvance =
|
||||
GetAdvanceAppUnits(advanceStart, aGlyphs + aGlyphCount - advanceStart, aAppUnitsPerDevUnit);
|
||||
// Should pass unmatchedness here but for now we'll just not tell the textrun
|
||||
// whether these are "missing glyph" glyphs or not
|
||||
aRun->SetDetailedGlyphs(index, detailedGlyphs.Elements(), detailedGlyphs.Length());
|
||||
}
|
||||
|
||||
|
@ -653,7 +664,8 @@ PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun,
|
|||
aString[stringTailOffset] == ' ') {
|
||||
SetGlyphsForCharacterGroup(glyphRecords + numGlyphs - 1, 1,
|
||||
baselineDeltas ? baselineDeltas + numGlyphs - 1 : nsnull,
|
||||
appUnitsPerDevUnit, aRun);
|
||||
appUnitsPerDevUnit, aRun, aUnmatched,
|
||||
aString);
|
||||
--stringTailOffset;
|
||||
--numGlyphs;
|
||||
}
|
||||
|
@ -663,7 +675,8 @@ PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun,
|
|||
aString[stringTailOffset] == ' ') {
|
||||
SetGlyphsForCharacterGroup(glyphRecords, 1,
|
||||
baselineDeltas,
|
||||
appUnitsPerDevUnit, aRun);
|
||||
appUnitsPerDevUnit, aRun, aUnmatched,
|
||||
aString);
|
||||
--stringTailOffset;
|
||||
--numGlyphs;
|
||||
++glyphRecords;
|
||||
|
@ -709,11 +722,13 @@ PostLayoutCallback(ATSULineRef aLine, gfxTextRun *aRun,
|
|||
SetGlyphsForCharacterGroup(glyphRecords + numGlyphs - glyphCount,
|
||||
glyphCount,
|
||||
baselineDeltas ? baselineDeltas + numGlyphs - glyphCount : nsnull,
|
||||
appUnitsPerDevUnit, aRun);
|
||||
appUnitsPerDevUnit, aRun, aUnmatched,
|
||||
aString);
|
||||
} else {
|
||||
SetGlyphsForCharacterGroup(glyphRecords,
|
||||
glyphCount, baselineDeltas,
|
||||
appUnitsPerDevUnit, aRun);
|
||||
appUnitsPerDevUnit, aRun, aUnmatched,
|
||||
aString);
|
||||
glyphRecords += glyphCount;
|
||||
if (baselineDeltas) {
|
||||
baselineDeltas += glyphCount;
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "prtypes.h"
|
||||
#include "gfxTypes.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxFontMissingGlyphs.h"
|
||||
|
||||
#include "cairo.h"
|
||||
#include "gfxFontTest.h"
|
||||
|
@ -128,8 +129,25 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
|
|||
break;
|
||||
++details;
|
||||
}
|
||||
} else if (glyphData->IsMissing()) {
|
||||
const gfxTextRun::DetailedGlyph *details = aTextRun->GetDetailedGlyphs(i);
|
||||
if (details) {
|
||||
double advance = details->mAdvance;
|
||||
if (!aDrawToPath) {
|
||||
gfxPoint pt(ToDeviceUnits(x, devUnitsPerAppUnit),
|
||||
ToDeviceUnits(y, devUnitsPerAppUnit));
|
||||
gfxFloat advanceDevUnits = ToDeviceUnits(advance, devUnitsPerAppUnit);
|
||||
if (isRTL) {
|
||||
pt.x -= advanceDevUnits;
|
||||
}
|
||||
// Every other glyph type (including missing glyphs) is ignored
|
||||
gfxFloat height = GetMetrics().maxAscent;
|
||||
gfxRect glyphRect(pt.x, pt.y - height, advanceDevUnits, height);
|
||||
gfxFontMissingGlyphs::DrawMissingGlyph(aContext, glyphRect, details->mGlyphID);
|
||||
}
|
||||
x += direction*advance;
|
||||
}
|
||||
}
|
||||
// Every other glyph type is ignored
|
||||
if (aSpacing) {
|
||||
double space = aSpacing[i - aStart].mAfter;
|
||||
if (i + 1 < aEnd) {
|
||||
|
@ -175,9 +193,9 @@ gfxFont::Measure(gfxTextRun *aTextRun,
|
|||
++clusterCount;
|
||||
if (g.IsSimpleGlyph()) {
|
||||
advance += charGlyphs[i].GetSimpleAdvance();
|
||||
} else if (g.IsComplexCluster()) {
|
||||
} else if (g.IsComplexOrMissing()) {
|
||||
const gfxTextRun::DetailedGlyph *details = aTextRun->GetDetailedGlyphs(i);
|
||||
for (;;) {
|
||||
while (details) {
|
||||
advance += details->mAdvance;
|
||||
if (details->mIsLastGlyph)
|
||||
break;
|
||||
|
@ -653,14 +671,14 @@ gfxTextRun::GetAdjustedSpacing(PRUint32 aStart, PRUint32 aEnd,
|
|||
aSpacing[i - 1 - aStart].mAfter -= clusterWidth;
|
||||
}
|
||||
clusterWidth = glyphData->GetSimpleAdvance();
|
||||
} else if (glyphData->IsComplexCluster()) {
|
||||
} else if (glyphData->IsComplexOrMissing()) {
|
||||
NS_ASSERTION(mDetailedGlyphs, "No details but we have a complex cluster...");
|
||||
if (i > aStart) {
|
||||
aSpacing[i - 1 - aStart].mAfter -= clusterWidth;
|
||||
}
|
||||
DetailedGlyph *details = mDetailedGlyphs[i];
|
||||
clusterWidth = 0;
|
||||
for (;;) {
|
||||
while (details) {
|
||||
clusterWidth += details->mAdvance;
|
||||
if (details->mIsLastGlyph)
|
||||
break;
|
||||
|
@ -1135,10 +1153,10 @@ gfxTextRun::BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength,
|
|||
CompressedGlyph *glyphData = &charGlyphs[i];
|
||||
if (glyphData->IsSimpleGlyph()) {
|
||||
advance += glyphData->GetSimpleAdvance();
|
||||
} else if (glyphData->IsComplexCluster()) {
|
||||
} else if (glyphData->IsComplexOrMissing()) {
|
||||
NS_ASSERTION(mDetailedGlyphs, "No details but we have a complex cluster...");
|
||||
DetailedGlyph *details = mDetailedGlyphs[i];
|
||||
for (;;) {
|
||||
while (details) {
|
||||
advance += details->mAdvance;
|
||||
if (details->mIsLastGlyph)
|
||||
break;
|
||||
|
@ -1230,10 +1248,9 @@ gfxTextRun::GetAdvanceWidth(PRUint32 aStart, PRUint32 aLength,
|
|||
CompressedGlyph *glyphData = &charGlyphs[i];
|
||||
if (glyphData->IsSimpleGlyph()) {
|
||||
result += glyphData->GetSimpleAdvance();
|
||||
} else if (glyphData->IsComplexCluster()) {
|
||||
NS_ASSERTION(mDetailedGlyphs, "No details but we have a complex cluster...");
|
||||
} else if (glyphData->IsComplexOrMissing()) {
|
||||
DetailedGlyph *details = mDetailedGlyphs[i];
|
||||
for (;;) {
|
||||
while (details) {
|
||||
result += details->mAdvance;
|
||||
if (details->mIsLastGlyph)
|
||||
break;
|
||||
|
@ -1307,6 +1324,28 @@ gfxTextRun::CountMissingGlyphs()
|
|||
return count;
|
||||
}
|
||||
|
||||
gfxTextRun::DetailedGlyph *
|
||||
gfxTextRun::AllocateDetailedGlyphs(PRUint32 aIndex, PRUint32 aCount)
|
||||
{
|
||||
if (!mCharacterGlyphs)
|
||||
return nsnull;
|
||||
|
||||
if (!mDetailedGlyphs) {
|
||||
mDetailedGlyphs = new nsAutoArrayPtr<DetailedGlyph>[mCharacterCount];
|
||||
if (!mDetailedGlyphs) {
|
||||
mCharacterGlyphs[aIndex].SetMissing();
|
||||
return nsnull;
|
||||
}
|
||||
}
|
||||
DetailedGlyph *details = new DetailedGlyph[aCount];
|
||||
if (!details) {
|
||||
mCharacterGlyphs[aIndex].SetMissing();
|
||||
return nsnull;
|
||||
}
|
||||
mDetailedGlyphs[aIndex] = details;
|
||||
return details;
|
||||
}
|
||||
|
||||
void
|
||||
gfxTextRun::SetDetailedGlyphs(PRUint32 aIndex, const DetailedGlyph *aGlyphs,
|
||||
PRUint32 aCount)
|
||||
|
@ -1314,27 +1353,32 @@ gfxTextRun::SetDetailedGlyphs(PRUint32 aIndex, const DetailedGlyph *aGlyphs,
|
|||
NS_ASSERTION(aCount > 0, "Can't set zero detailed glyphs");
|
||||
NS_ASSERTION(aGlyphs[aCount - 1].mIsLastGlyph, "Failed to set last glyph flag");
|
||||
|
||||
if (!mCharacterGlyphs)
|
||||
DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, aCount);
|
||||
if (!details)
|
||||
return;
|
||||
|
||||
if (!mDetailedGlyphs) {
|
||||
mDetailedGlyphs = new nsAutoArrayPtr<DetailedGlyph>[mCharacterCount];
|
||||
if (!mDetailedGlyphs) {
|
||||
mCharacterGlyphs[aIndex].SetMissing();
|
||||
return;
|
||||
}
|
||||
}
|
||||
DetailedGlyph *details = new DetailedGlyph[aCount];
|
||||
if (!details) {
|
||||
mCharacterGlyphs[aIndex].SetMissing();
|
||||
return;
|
||||
}
|
||||
memcpy(details, aGlyphs, sizeof(DetailedGlyph)*aCount);
|
||||
|
||||
mDetailedGlyphs[aIndex] = details;
|
||||
mCharacterGlyphs[aIndex].SetComplexCluster();
|
||||
}
|
||||
|
||||
void
|
||||
gfxTextRun::SetMissingGlyph(PRUint32 aIndex, PRUnichar aChar)
|
||||
{
|
||||
DetailedGlyph *details = AllocateDetailedGlyphs(aIndex, 1);
|
||||
if (!details)
|
||||
return;
|
||||
|
||||
details->mIsLastGlyph = PR_TRUE;
|
||||
details->mGlyphID = aChar;
|
||||
GlyphRun *glyphRun = &mGlyphRuns[FindFirstGlyphRunContaining(aIndex)];
|
||||
gfxFloat width = PR_MAX(glyphRun->mFont->GetMetrics().aveCharWidth,
|
||||
gfxFontMissingGlyphs::GetDesiredMinWidth());
|
||||
details->mAdvance = PRUint32(width*GetAppUnitsPerDevUnit());
|
||||
details->mXOffset = 0;
|
||||
details->mYOffset = 0;
|
||||
mCharacterGlyphs[aIndex].SetMissing();
|
||||
}
|
||||
|
||||
void
|
||||
gfxTextRun::RecordSurrogates(const PRUnichar *aString)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,261 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Corporation code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2007
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Robert O'Callahan <robert@ocallahan.org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "gfxFontMissingGlyphs.h"
|
||||
|
||||
#define CHAR_BITS(b00, b01, b02, b10, b11, b12, b20, b21, b22, b30, b31, b32, b40, b41, b42) \
|
||||
((b00 << 0) | (b01 << 1) | (b02 << 2) | (b10 << 3) | (b11 << 4) | (b12 << 5) | \
|
||||
(b20 << 6) | (b21 << 7) | (b22 << 8) | (b30 << 9) | (b31 << 10) | (b32 << 11) | \
|
||||
(b40 << 12) | (b41 << 13) | (b42 << 14))
|
||||
|
||||
static const PRUint16 glyphMicroFont[16] = {
|
||||
CHAR_BITS(0, 1, 0,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
0, 1, 0),
|
||||
CHAR_BITS(0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0),
|
||||
CHAR_BITS(1, 1, 1,
|
||||
0, 0, 1,
|
||||
1, 1, 1,
|
||||
1, 0, 0,
|
||||
1, 1, 1),
|
||||
CHAR_BITS(1, 1, 1,
|
||||
0, 0, 1,
|
||||
1, 1, 1,
|
||||
0, 0, 1,
|
||||
1, 1, 1),
|
||||
CHAR_BITS(1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
0, 0, 1,
|
||||
0, 0, 1),
|
||||
CHAR_BITS(1, 1, 1,
|
||||
1, 0, 0,
|
||||
1, 1, 1,
|
||||
0, 0, 1,
|
||||
1, 1, 1),
|
||||
CHAR_BITS(1, 1, 1,
|
||||
1, 0, 0,
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1),
|
||||
CHAR_BITS(1, 1, 1,
|
||||
0, 0, 1,
|
||||
0, 0, 1,
|
||||
0, 0, 1,
|
||||
0, 0, 1),
|
||||
CHAR_BITS(1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1),
|
||||
CHAR_BITS(1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
0, 0, 1,
|
||||
0, 0, 1),
|
||||
CHAR_BITS(1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 1),
|
||||
CHAR_BITS(1, 1, 0,
|
||||
1, 0, 1,
|
||||
1, 1, 0,
|
||||
1, 0, 1,
|
||||
1, 1, 0),
|
||||
CHAR_BITS(0, 1, 1,
|
||||
1, 0, 0,
|
||||
1, 0, 0,
|
||||
1, 0, 0,
|
||||
0, 1, 1),
|
||||
CHAR_BITS(1, 1, 0,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 0),
|
||||
CHAR_BITS(1, 1, 1,
|
||||
1, 0, 0,
|
||||
1, 1, 1,
|
||||
1, 0, 0,
|
||||
1, 1, 1),
|
||||
CHAR_BITS(1, 1, 1,
|
||||
1, 0, 0,
|
||||
1, 1, 1,
|
||||
1, 0, 0,
|
||||
1, 0, 0)
|
||||
};
|
||||
|
||||
/* Parameters that control the rendering of hexboxes. They look like this:
|
||||
|
||||
+---------+
|
||||
| |
|
||||
| HHH HHH |
|
||||
| HHH HHH |
|
||||
| HHH HHH |
|
||||
| HHH HHH |
|
||||
| HHH HHH |
|
||||
| |
|
||||
| HHH HHH |
|
||||
| HHH HHH |
|
||||
| HHH HHH |
|
||||
| HHH HHH |
|
||||
| HHH HHH |
|
||||
| |
|
||||
+---------+
|
||||
*/
|
||||
|
||||
/** Width of a minifont glyph (see above) */
|
||||
static const int MINIFONT_WIDTH = 3;
|
||||
/** Height of a minifont glyph (see above) */
|
||||
static const int MINIFONT_HEIGHT = 5;
|
||||
/**
|
||||
* Gap between minifont glyphs (both horizontal and vertical) and also
|
||||
* the minimum desired gap between the box border and the glyphs
|
||||
*/
|
||||
static const int HEX_CHAR_GAP = 1;
|
||||
/**
|
||||
* The amount of space between the vertical edge of the glyphbox and the
|
||||
* box border. We make this nonzero so that when multiple missing glyphs
|
||||
* occur consecutively there's a gap between their rendered boxes.
|
||||
*/
|
||||
static const int BOX_HORIZONTAL_INSET = 1;
|
||||
/** The width of the border */
|
||||
static const int BOX_BORDER_WIDTH = 1;
|
||||
/**
|
||||
* The scaling factor for the border opacity; this is multiplied by the current
|
||||
* opacity being used to draw the text.
|
||||
*/
|
||||
static const gfxFloat BOX_BORDER_OPACITY = 0.5;
|
||||
/**
|
||||
* The minimum desired width for a missing-glyph glyph box. I've laid it out
|
||||
* like this so you can see what goes where.
|
||||
*/
|
||||
static const int MIN_DESIRED_WIDTH =
|
||||
BOX_HORIZONTAL_INSET + BOX_BORDER_WIDTH + HEX_CHAR_GAP +
|
||||
MINIFONT_WIDTH + HEX_CHAR_GAP + MINIFONT_WIDTH +
|
||||
HEX_CHAR_GAP + BOX_BORDER_WIDTH + BOX_HORIZONTAL_INSET;
|
||||
|
||||
/**
|
||||
* Draw a single hex character using the current color. A nice way to do this
|
||||
* would be to fill in an A8 image surface and then use it as a mask
|
||||
* to paint the current color. Tragically this doesn't currently work with the
|
||||
* Quartz cairo backend which doesn't generally support masking with surfaces.
|
||||
* So for now we just paint a bunch of rectangles...
|
||||
*/
|
||||
static void
|
||||
DrawHexChar(gfxContext *aContext, const gfxPoint& aPt, PRUint32 aDigit)
|
||||
{
|
||||
aContext->NewPath();
|
||||
PRUint32 glyphBits = glyphMicroFont[aDigit];
|
||||
int x, y;
|
||||
for (y = 0; y < MINIFONT_HEIGHT; ++y) {
|
||||
for (x = 0; x < MINIFONT_WIDTH; ++x) {
|
||||
if (glyphBits & 1) {
|
||||
aContext->Rectangle(gfxRect(x, y, 1, 1) + aPt, PR_TRUE);
|
||||
}
|
||||
glyphBits >>= 1;
|
||||
}
|
||||
}
|
||||
aContext->Fill();
|
||||
}
|
||||
|
||||
void
|
||||
gfxFontMissingGlyphs::DrawMissingGlyph(gfxContext *aContext, const gfxRect& aRect,
|
||||
PRUnichar aChar)
|
||||
{
|
||||
aContext->Save();
|
||||
|
||||
gfxRGBA currentColor;
|
||||
if (!aContext->GetColor(currentColor)) {
|
||||
// We're currently drawing with some kind of pattern... Just draw
|
||||
// the missing-glyph data in black.
|
||||
currentColor = gfxRGBA(0,0,0,1);
|
||||
}
|
||||
|
||||
// Stroke a rectangle so that the stroke's left edge is inset one pixel
|
||||
// from the left edge of the glyph box and the stroke's right edge
|
||||
// is inset one pixel from the right edge of the glyph box.
|
||||
gfxFloat halfBorderWidth = BOX_BORDER_WIDTH/2.0;
|
||||
gfxFloat borderLeft = aRect.X() + BOX_HORIZONTAL_INSET + halfBorderWidth;
|
||||
gfxFloat borderRight = aRect.XMost() - BOX_HORIZONTAL_INSET - halfBorderWidth;
|
||||
gfxRect borderStrokeRect(borderLeft, aRect.Y() + halfBorderWidth,
|
||||
borderRight - borderLeft, aRect.Height() - 2*halfBorderWidth);
|
||||
if (!borderStrokeRect.IsEmpty()) {
|
||||
aContext->SetLineWidth(BOX_BORDER_WIDTH);
|
||||
aContext->SetDash(gfxContext::gfxLineSolid);
|
||||
aContext->SetLineCap(gfxContext::LINE_CAP_SQUARE);
|
||||
aContext->SetLineJoin(gfxContext::LINE_JOIN_MITER);
|
||||
gfxRGBA color = currentColor;
|
||||
color.a *= BOX_BORDER_OPACITY;
|
||||
aContext->SetColor(color);
|
||||
aContext->NewPath();
|
||||
aContext->Rectangle(borderStrokeRect);
|
||||
aContext->Stroke();
|
||||
}
|
||||
|
||||
if (aRect.Width() >= 2*MINIFONT_WIDTH + HEX_CHAR_GAP &&
|
||||
aRect.Height() >= 2*MINIFONT_HEIGHT + HEX_CHAR_GAP) {
|
||||
aContext->SetColor(currentColor);
|
||||
gfxPoint center(aRect.X() + aRect.Width()/2,
|
||||
aRect.Y() + aRect.Height()/2);
|
||||
gfxFloat halfGap = HEX_CHAR_GAP/2.0;
|
||||
gfxFloat left = -(MINIFONT_WIDTH + halfGap);
|
||||
gfxFloat top = -(MINIFONT_HEIGHT + halfGap);
|
||||
DrawHexChar(aContext,
|
||||
center + gfxPoint(left, top), (aChar >> 12) & 0xF);
|
||||
DrawHexChar(aContext,
|
||||
center + gfxPoint(halfGap, top), (aChar >> 8) & 0xF);
|
||||
DrawHexChar(aContext,
|
||||
center + gfxPoint(left, halfGap), (aChar >> 4) & 0xF);
|
||||
DrawHexChar(aContext,
|
||||
center + gfxPoint(halfGap, halfGap), aChar & 0xF);
|
||||
}
|
||||
|
||||
aContext->Restore();
|
||||
}
|
||||
|
||||
gfxFloat
|
||||
gfxFontMissingGlyphs::GetDesiredMinWidth()
|
||||
{
|
||||
return MIN_DESIRED_WIDTH;
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Corporation code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2007
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Robert O'Callahan <robert@ocallahan.org>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef GFX_FONTMISSINGGLYPHS_H
|
||||
#define GFX_FONTMISSINGGLYPHS_H
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "gfxTypes.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxRect.h"
|
||||
|
||||
/**
|
||||
* This class should not be instantiated. It's just a container
|
||||
* for some helper functions.
|
||||
*/
|
||||
class THEBES_API gfxFontMissingGlyphs {
|
||||
public:
|
||||
/**
|
||||
* Draw hexboxes for a missing glyph.
|
||||
* @param aContext the context to draw to
|
||||
* @param aRect the glyph-box for the glyph that is missing
|
||||
* @param aChar the UTF16 codepoint for the character
|
||||
*/
|
||||
static void DrawMissingGlyph(gfxContext *aContext, const gfxRect& aRect,
|
||||
PRUnichar aChar);
|
||||
/**
|
||||
* @return the desired minimum width for a glyph-box that will allow
|
||||
* the hexboxes to be drawn reasonably.
|
||||
*/
|
||||
static gfxFloat GetDesiredMinWidth();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -940,8 +940,23 @@ ConvertPangoToAppUnits(PRInt32 aCoordinate, PRUint32 aAppUnitsPerDevUnit)
|
|||
return PRInt32(v);
|
||||
}
|
||||
|
||||
static void
|
||||
SetMissingGlyphForUCS4(gfxTextRun *aTextRun, PRUint32 aIndex, gunichar aCh)
|
||||
{
|
||||
if (aCh < 0x10000) {
|
||||
aTextRun->SetMissingGlyph(aIndex, PRUnichar(aCh));
|
||||
return;
|
||||
}
|
||||
|
||||
// Display non-BMP characters as a surrogate pair
|
||||
aTextRun->SetMissingGlyph(aIndex, H_SURROGATE(aCh));
|
||||
if (aIndex + 1 < aTextRun->GetLength()) {
|
||||
aTextRun->SetMissingGlyph(aIndex + 1, L_SURROGATE(aCh));
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
gfxPangoFontGroup::SetGlyphs(gfxTextRun* aTextRun,
|
||||
gfxPangoFontGroup::SetGlyphs(gfxTextRun *aTextRun,
|
||||
const gchar *aUTF8, PRUint32 aUTF8Length,
|
||||
PRUint32 *aUTF16Offset, PangoGlyphString *aGlyphs,
|
||||
PangoGlyphUnit aOverrideSpaceWidth,
|
||||
|
@ -966,9 +981,11 @@ gfxPangoFontGroup::SetGlyphs(gfxTextRun* aTextRun,
|
|||
NS_ERROR("Someone has added too many glyphs!");
|
||||
break;
|
||||
}
|
||||
if (aUTF8[index] == 0) {
|
||||
// treat this null byte as a missing glyph
|
||||
aTextRun->SetCharacterGlyph(utf16Offset, g.SetMissing());
|
||||
gunichar ch = g_utf8_get_char(aUTF8 + index);
|
||||
if (ch == 0) {
|
||||
// treat this null byte as a missing glyph. Pango doesn't create
|
||||
// glyphs for these, not even missing-glyph glyphIDs.
|
||||
aTextRun->SetMissingGlyph(utf16Offset, 0);
|
||||
} else if (glyphCount == numGlyphs ||
|
||||
PRUint32(logClusters[glyphIndex]) > index) {
|
||||
// No glyphs for this cluster, and it's not a null byte.
|
||||
|
@ -1018,7 +1035,7 @@ gfxPangoFontGroup::SetGlyphs(gfxTextRun* aTextRun,
|
|||
} else if (haveMissingGlyph) {
|
||||
// Note that missing-glyph IDs are not simple glyph IDs, so we'll
|
||||
// always get here when a glyph is missing
|
||||
aTextRun->SetCharacterGlyph(utf16Offset, g.SetMissing());
|
||||
SetMissingGlyphForUCS4(aTextRun, utf16Offset, ch);
|
||||
} else {
|
||||
if (detailedGlyphs.Length() < glyphClusterCount) {
|
||||
if (!detailedGlyphs.AppendElements(glyphClusterCount - detailedGlyphs.Length()))
|
||||
|
@ -1044,7 +1061,6 @@ gfxPangoFontGroup::SetGlyphs(gfxTextRun* aTextRun,
|
|||
}
|
||||
}
|
||||
|
||||
gunichar ch = g_utf8_get_char(aUTF8 + index);
|
||||
++utf16Offset;
|
||||
NS_ASSERTION(!IS_SURROGATE(ch), "surrogates should not appear in UTF8");
|
||||
if (ch >= 0x10000) {
|
||||
|
@ -1071,13 +1087,16 @@ gfxPangoFontGroup::CreateGlyphRunsXft(gfxTextRun *aTextRun,
|
|||
gfxTextRun::CompressedGlyph g;
|
||||
const PRUint32 appUnitsPerDevUnit = aTextRun->GetAppUnitsPerDevUnit();
|
||||
|
||||
aTextRun->AddGlyphRun(font, 0);
|
||||
|
||||
while (p < aUTF8 + aUTF8Length) {
|
||||
gunichar ch = g_utf8_get_char(p);
|
||||
p = g_utf8_next_char(p);
|
||||
|
||||
if (ch == 0) {
|
||||
// treat this null byte as a missing glyph
|
||||
aTextRun->SetCharacterGlyph(utf16Offset, g.SetMissing());
|
||||
// treat this null byte as a missing glyph. Pango
|
||||
// doesn't create glyphs for these, not even missing-glyphs.
|
||||
aTextRun->SetMissingGlyph(utf16Offset, 0);
|
||||
} else {
|
||||
FT_UInt glyph = XftCharIndex(dpy, xfont, ch);
|
||||
XGlyphInfo info;
|
||||
|
@ -1095,7 +1114,7 @@ gfxPangoFontGroup::CreateGlyphRunsXft(gfxTextRun *aTextRun,
|
|||
} else if (IS_MISSING_GLYPH(glyph)) {
|
||||
// Note that missing-glyph IDs are not simple glyph IDs, so we'll
|
||||
// always get here when a glyph is missing
|
||||
aTextRun->SetCharacterGlyph(utf16Offset, g.SetMissing());
|
||||
SetMissingGlyphForUCS4(aTextRun, utf16Offset, ch);
|
||||
} else {
|
||||
gfxTextRun::DetailedGlyph details;
|
||||
details.mIsLastGlyph = PR_TRUE;
|
||||
|
@ -1117,7 +1136,6 @@ gfxPangoFontGroup::CreateGlyphRunsXft(gfxTextRun *aTextRun,
|
|||
|
||||
++utf16Offset;
|
||||
}
|
||||
aTextRun->AddGlyphRun(font, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1179,14 +1197,12 @@ gfxPangoFontGroup::CreateGlyphRunsFast(gfxTextRun *aTextRun,
|
|||
pango_shape(aUTF8, aUTF8Length, &analysis, glyphString);
|
||||
|
||||
PRUint32 utf16Offset = 0;
|
||||
nsresult rv = SetGlyphs(aTextRun, aUTF8, aUTF8Length, &utf16Offset, glyphString, 0, PR_TRUE);
|
||||
|
||||
pango_glyph_string_free(glyphString);
|
||||
|
||||
nsresult rv = aTextRun->AddGlyphRun(font, 0);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
return aTextRun->AddGlyphRun(font, 0);
|
||||
rv = SetGlyphs(aTextRun, aUTF8, aUTF8Length, &utf16Offset, glyphString, 0, PR_TRUE);
|
||||
pango_glyph_string_free(glyphString);
|
||||
return rv;
|
||||
}
|
||||
|
||||
class FontSelector
|
||||
|
@ -1258,11 +1274,14 @@ public:
|
|||
mItem->analysis.font = tmpFont;
|
||||
}
|
||||
|
||||
nsresult rv = mTextRun->AddGlyphRun(aFont, incomingUTF16Offset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
mGroup->SetGlyphs(mTextRun, mString + mSegmentOffset, aUTF8Length, &mUTF16Offset,
|
||||
aGlyphs, mSpaceWidth, PR_FALSE);
|
||||
|
||||
mSegmentOffset += aUTF8Length;
|
||||
return mTextRun->AddGlyphRun(aFont, incomingUTF16Offset);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -1132,6 +1132,8 @@ public:
|
|||
PRUint32 offsetInRun = mScriptItem->iCharPos;
|
||||
SetupClusterBoundaries(aRun, offsetInRun);
|
||||
|
||||
aRun->AddGlyphRun(GetCurrentFont(), offsetInRun);
|
||||
|
||||
// XXX We should store this in the item and only fetch it once
|
||||
SCRIPT_FONTPROPERTIES sfp;
|
||||
ScriptFontProperties(&sfp);
|
||||
|
@ -1168,7 +1170,7 @@ public:
|
|||
PRInt32 advance = mAdvances[k]*appUnitsPerDevUnit;
|
||||
WORD glyph = mGlyphs[k];
|
||||
if (missing) {
|
||||
aRun->SetCharacterGlyph(runOffset, g.SetMissing());
|
||||
aRun->SetMissingGlyph(runOffset, mString[offset]);
|
||||
} else if (glyphCount == 1 && advance >= 0 &&
|
||||
mOffsets[k].dv == 0 && mOffsets[k].du == 0 &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
|
@ -1193,8 +1195,6 @@ public:
|
|||
}
|
||||
++offset;
|
||||
}
|
||||
|
||||
aRun->AddGlyphRun(GetCurrentFont(), offsetInRun);
|
||||
}
|
||||
|
||||
gfxWindowsFont *GetNextFont() {
|
||||
|
|
Загрузка…
Ссылка в новой задаче