Bug 372629. Draw missing-glyph boxes with the Unicode character inscribed in hex. r=pavlov

This commit is contained in:
roc+@cs.cmu.edu 2007-03-26 20:24:49 -07:00
Родитель e564057cca
Коммит c89d0c6fcc
8 изменённых файлов: 471 добавлений и 54 удалений

Просмотреть файл

@ -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;
}
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 (including missing glyphs) is ignored
// 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,26 +1353,31 @@ 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);
return rv;
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() {