зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1479196 - draw missing glyphs from an atlas instead of rectangles. r=jfkthame
This commit is contained in:
Родитель
daa9f58360
Коммит
bf12f26ad9
|
@ -78,7 +78,9 @@ public:
|
|||
{
|
||||
for (int i=0; i<count; i++) {
|
||||
if (key == entries[i].key) {
|
||||
entries[i].destroy(entries[i].userData);
|
||||
if (entries[i].destroy) {
|
||||
entries[i].destroy(entries[i].userData);
|
||||
}
|
||||
// decrement before looping so entries[i+1] doesn't read past the end:
|
||||
--count;
|
||||
for (;i<count; i++) {
|
||||
|
|
|
@ -9,107 +9,31 @@
|
|||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/Helpers.h"
|
||||
#include "mozilla/gfx/PathHelpers.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsDeviceContext.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "TextDrawTarget.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
#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 uint16_t 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(0, 1, 0,
|
||||
1, 0, 1,
|
||||
0, 1, 0,
|
||||
1, 0, 1,
|
||||
0, 1, 0),
|
||||
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)
|
||||
#define X 255
|
||||
static const uint8_t gMiniFontData[] = {
|
||||
0,X,0, 0,X,0, X,X,X, X,X,X, X,0,X, X,X,X, X,X,X, X,X,X, X,X,X, X,X,X, X,X,X, X,X,0, 0,X,X, X,X,0, X,X,X, X,X,X,
|
||||
X,0,X, 0,X,0, 0,0,X, 0,0,X, X,0,X, X,0,0, X,0,0, 0,0,X, X,0,X, X,0,X, X,0,X, X,0,X, X,0,0, X,0,X, X,0,0, X,0,0,
|
||||
X,0,X, 0,X,0, X,X,X, X,X,X, X,X,X, X,X,X, X,X,X, 0,0,X, X,X,X, X,X,X, X,X,X, X,X,0, X,0,0, X,0,X, X,X,X, X,X,X,
|
||||
X,0,X, 0,X,0, X,0,0, 0,0,X, 0,0,X, 0,0,X, X,0,X, 0,0,X, X,0,X, 0,0,X, X,0,X, X,0,X, X,0,0, X,0,X, X,0,0, X,0,0,
|
||||
0,X,0, 0,X,0, X,X,X, X,X,X, 0,0,X, X,X,X, X,X,X, 0,0,X, X,X,X, 0,0,X, X,0,X, X,X,0, 0,X,X, X,X,0, X,X,X, X,0,0,
|
||||
};
|
||||
#undef X
|
||||
|
||||
/* Parameters that control the rendering of hexboxes. They look like this:
|
||||
|
||||
BMP codepoints non-BMP codepoints
|
||||
(U+0000 - U+FFFF) (U+10000 - U+10FFFF)
|
||||
|
||||
+---------+ +-------------+
|
||||
+---------+ +-------------+
|
||||
| | | |
|
||||
| HHH HHH | | HHH HHH HHH |
|
||||
| HHH HHH | | HHH HHH HHH |
|
||||
|
@ -148,67 +72,317 @@ static const int BOX_BORDER_WIDTH = 1;
|
|||
* opacity being used to draw the text.
|
||||
*/
|
||||
static const Float BOX_BORDER_OPACITY = 0.5;
|
||||
/**
|
||||
* 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...
|
||||
*/
|
||||
|
||||
#ifndef MOZ_GFX_OPTIMIZE_MOBILE
|
||||
static void
|
||||
DrawHexChar(uint32_t aDigit, const Point& aPt, DrawTarget& aDrawTarget,
|
||||
const Pattern &aPattern, const Matrix* aMat)
|
||||
|
||||
static RefPtr<DrawTarget> gGlyphDrawTarget;
|
||||
static RefPtr<SourceSurface> gGlyphMask;
|
||||
static RefPtr<SourceSurface> gGlyphAtlas;
|
||||
static Color gGlyphColor;
|
||||
|
||||
/**
|
||||
* Generates a new colored mini-font atlas from the mini-font mask.
|
||||
*/
|
||||
static bool
|
||||
MakeGlyphAtlas(const Color& aColor)
|
||||
{
|
||||
uint32_t glyphBits = glyphMicroFont[aDigit];
|
||||
|
||||
if (aMat) {
|
||||
// If using an orientation matrix instead of a DT transform, step
|
||||
// with the matrix basis vectors, filling individual rectangles of
|
||||
// the size indicated by the matrix.
|
||||
Point stepX(aMat->_11, aMat->_12);
|
||||
Point stepY(aMat->_21, aMat->_22);
|
||||
Point corner = stepX + stepY;
|
||||
// Get the rectangle at the origin that will be stepped into place.
|
||||
Rect startRect(std::min(corner.x, 0.0f), std::min(corner.y, 0.0f),
|
||||
fabs(corner.x), fabs(corner.y));
|
||||
startRect.MoveBy(aMat->TransformPoint(aPt));
|
||||
for (int y = 0; y < MINIFONT_HEIGHT; ++y) {
|
||||
Rect curRect = startRect;
|
||||
for (int x = 0; x < MINIFONT_WIDTH; ++x) {
|
||||
if (glyphBits & 1) {
|
||||
aDrawTarget.FillRect(curRect, aPattern);
|
||||
}
|
||||
glyphBits >>= 1;
|
||||
curRect.MoveBy(stepX);
|
||||
}
|
||||
startRect.MoveBy(stepY);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// To avoid the potential for seams showing between rects when we're under
|
||||
// a transform we concat all the rects into a PathBuilder and fill the
|
||||
// resulting Path (rather than using DrawTarget::FillRect).
|
||||
RefPtr<PathBuilder> builder = aDrawTarget.CreatePathBuilder();
|
||||
for (int y = 0; y < MINIFONT_HEIGHT; ++y) {
|
||||
for (int x = 0; x < MINIFONT_WIDTH; ++x) {
|
||||
if (glyphBits & 1) {
|
||||
Rect r(aPt.x + x, aPt.y + y, 1, 1);
|
||||
MaybeSnapToDevicePixels(r, aDrawTarget, true);
|
||||
builder->MoveTo(r.TopLeft());
|
||||
builder->LineTo(r.TopRight());
|
||||
builder->LineTo(r.BottomRight());
|
||||
builder->LineTo(r.BottomLeft());
|
||||
builder->Close();
|
||||
}
|
||||
glyphBits >>= 1;
|
||||
gGlyphAtlas = nullptr;
|
||||
if (!gGlyphDrawTarget) {
|
||||
gGlyphDrawTarget = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
|
||||
IntSize(MINIFONT_WIDTH * 16, MINIFONT_HEIGHT), SurfaceFormat::B8G8R8A8);
|
||||
if (!gGlyphDrawTarget) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
RefPtr<Path> path = builder->Finish();
|
||||
aDrawTarget.Fill(path, aPattern);
|
||||
if (!gGlyphMask) {
|
||||
gGlyphMask = gGlyphDrawTarget->CreateSourceSurfaceFromData(
|
||||
const_cast<uint8_t*>(gMiniFontData), IntSize(MINIFONT_WIDTH * 16, MINIFONT_HEIGHT),
|
||||
MINIFONT_WIDTH * 16, SurfaceFormat::A8);
|
||||
if (!gGlyphMask) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
gGlyphDrawTarget->MaskSurface(ColorPattern(aColor), gGlyphMask, Point(0, 0),
|
||||
DrawOptions(1.0f, CompositionOp::OP_SOURCE));
|
||||
gGlyphAtlas = gGlyphDrawTarget->Snapshot();
|
||||
if (!gGlyphAtlas) {
|
||||
return false;
|
||||
}
|
||||
gGlyphColor = aColor;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reuse the current mini-font atlas if the color matches, otherwise regenerate it.
|
||||
*/
|
||||
static inline already_AddRefed<SourceSurface>
|
||||
GetGlyphAtlas(const Color& aColor)
|
||||
{
|
||||
// Get the opaque color, ignoring any transparency which will be handled later.
|
||||
Color color(aColor.r, aColor.g, aColor.b);
|
||||
if ((gGlyphAtlas && gGlyphColor == color) || MakeGlyphAtlas(color)) {
|
||||
return do_AddRef(gGlyphAtlas);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear any cached glyph atlas resources.
|
||||
*/
|
||||
static void
|
||||
PurgeGlyphAtlas()
|
||||
{
|
||||
gGlyphAtlas = nullptr;
|
||||
gGlyphDrawTarget = nullptr;
|
||||
gGlyphMask = nullptr;
|
||||
}
|
||||
|
||||
// WebRender layer manager user data that will get signaled when the layer
|
||||
// manager is destroyed.
|
||||
class WRUserData : public layers::LayerUserData, public LinkedListElement<WRUserData>
|
||||
{
|
||||
public:
|
||||
explicit WRUserData(layers::WebRenderLayerManager* aManager);
|
||||
|
||||
~WRUserData();
|
||||
|
||||
static void
|
||||
Assign(layers::WebRenderLayerManager* aManager)
|
||||
{
|
||||
if (!aManager->HasUserData(&sWRUserDataKey)) {
|
||||
aManager->SetUserData(&sWRUserDataKey, new WRUserData(aManager));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Remove()
|
||||
{
|
||||
remove();
|
||||
mManager->RemoveUserData(&sWRUserDataKey);
|
||||
}
|
||||
|
||||
layers::WebRenderLayerManager* mManager;
|
||||
|
||||
static UserDataKey sWRUserDataKey;
|
||||
};
|
||||
|
||||
static RefPtr<SourceSurface> gWRGlyphAtlas[8];
|
||||
static LinkedList<WRUserData> gWRUsers;
|
||||
UserDataKey WRUserData::sWRUserDataKey;
|
||||
|
||||
/**
|
||||
* Generates a transformed WebRender mini-font atlas for a given orientation.
|
||||
*/
|
||||
static already_AddRefed<SourceSurface>
|
||||
MakeWRGlyphAtlas(const Matrix* aMat)
|
||||
{
|
||||
IntSize size(MINIFONT_WIDTH * 16, MINIFONT_HEIGHT);
|
||||
// If the orientation is transposed, width/height are swapped.
|
||||
if (aMat && aMat->_11 == 0) {
|
||||
std::swap(size.width, size.height);
|
||||
}
|
||||
RefPtr<DrawTarget> ref = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
|
||||
RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->CreateSimilarSoftwareDrawTarget(
|
||||
ref, size, SurfaceFormat::B8G8R8A8);
|
||||
if (!dt) {
|
||||
return nullptr;
|
||||
}
|
||||
if (aMat) {
|
||||
// Select appropriate transform matrix based on whether the
|
||||
// orientation is transposed.
|
||||
dt->SetTransform(aMat->_11 == 0 ?
|
||||
Matrix(0.0f, copysign(1.0f, aMat->_12),
|
||||
copysign(1.0f, aMat->_21), 0.0f,
|
||||
aMat->_21 < 0 ? MINIFONT_HEIGHT : 0.0f,
|
||||
aMat->_12 < 0 ? MINIFONT_WIDTH * 16 : 0.0f) :
|
||||
Matrix(copysign(1.0f, aMat->_11), 0.0f,
|
||||
0.0f, copysign(1.0f, aMat->_22),
|
||||
aMat->_11 < 0 ? MINIFONT_WIDTH * 16 : 0.0f,
|
||||
aMat->_22 < 0 ? MINIFONT_HEIGHT : 0.0f));
|
||||
}
|
||||
RefPtr<SourceSurface> mask = dt->CreateSourceSurfaceFromData(
|
||||
const_cast<uint8_t*>(gMiniFontData), IntSize(MINIFONT_WIDTH * 16, MINIFONT_HEIGHT),
|
||||
MINIFONT_WIDTH * 16, SurfaceFormat::A8);
|
||||
if (!mask) {
|
||||
return nullptr;
|
||||
}
|
||||
dt->MaskSurface(ColorPattern(Color(1.0f, 1.0f, 1.0f)), mask, Point(0, 0));
|
||||
return dt->Snapshot();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear any cached WebRender glyph atlas resources.
|
||||
*/
|
||||
static void
|
||||
PurgeWRGlyphAtlas()
|
||||
{
|
||||
// For each WR layer manager, we need go through each atlas orientation
|
||||
// and see if it has a stashed image key. If it does, remove the image
|
||||
// from the layer manager.
|
||||
for (WRUserData* user : gWRUsers) {
|
||||
auto* manager = user->mManager;
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
if (gWRGlyphAtlas[i]) {
|
||||
uint32_t handle =
|
||||
(uint32_t)(uintptr_t)gWRGlyphAtlas[i]->GetUserData(
|
||||
reinterpret_cast<UserDataKey*>(manager));
|
||||
if (handle) {
|
||||
manager->AddImageKeyForDiscard(
|
||||
wr::ImageKey{manager->WrBridge()->GetNamespace(), handle});
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove the layer manager's destroy notification.
|
||||
user->Remove();
|
||||
}
|
||||
// Finally, clear out the atlases.
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
gWRGlyphAtlas[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
WRUserData::WRUserData(layers::WebRenderLayerManager* aManager)
|
||||
: mManager(aManager)
|
||||
{
|
||||
gWRUsers.insertFront(this);
|
||||
}
|
||||
|
||||
WRUserData::~WRUserData()
|
||||
{
|
||||
// When the layer manager is destroyed, we need go through each
|
||||
// atlas and remove any assigned image keys.
|
||||
if (isInList()) {
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
if (gWRGlyphAtlas[i]) {
|
||||
gWRGlyphAtlas[i]->RemoveUserData(reinterpret_cast<UserDataKey*>(mManager));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static already_AddRefed<SourceSurface>
|
||||
GetWRGlyphAtlas(DrawTarget& aDrawTarget, const Matrix* aMat)
|
||||
{
|
||||
uint32_t key = 0;
|
||||
// Encode orientation in the key.
|
||||
if (aMat) {
|
||||
if (aMat->_11 == 0) {
|
||||
key |= 4 | (aMat->_12 < 0 ? 1 : 0) | (aMat->_21 < 0 ? 2 : 0);
|
||||
} else {
|
||||
key |= (aMat->_11 < 0 ? 1 : 0) | (aMat->_22 < 0 ? 2 : 0);
|
||||
}
|
||||
}
|
||||
// Check if an atlas was already created, or create one if necessary.
|
||||
RefPtr<SourceSurface> atlas = gWRGlyphAtlas[key];
|
||||
if (!atlas) {
|
||||
atlas = MakeWRGlyphAtlas(aMat);
|
||||
gWRGlyphAtlas[key] = atlas;
|
||||
}
|
||||
// The atlas may exist, but an image key may not be assigned for it to
|
||||
// the given layer manager.
|
||||
auto* tdt = static_cast<layout::TextDrawTarget*>(&aDrawTarget);
|
||||
auto* manager = tdt->WrLayerManager();
|
||||
if (!atlas->GetUserData(reinterpret_cast<UserDataKey*>(manager))) {
|
||||
// No image key, so we need to map the atlas' data for transfer to WR.
|
||||
RefPtr<DataSourceSurface> dataSurface = atlas->GetDataSurface();
|
||||
if (!dataSurface) {
|
||||
return nullptr;
|
||||
}
|
||||
DataSourceSurface::ScopedMap map(dataSurface, DataSourceSurface::READ);
|
||||
if (!map.IsMapped()) {
|
||||
return nullptr;
|
||||
}
|
||||
// Transfer the data and get an image key for it.
|
||||
Maybe<wr::ImageKey> result =
|
||||
tdt->DefineImage(atlas->GetSize(),
|
||||
map.GetStride(),
|
||||
atlas->GetFormat(),
|
||||
map.GetData());
|
||||
if (!result.isSome()) {
|
||||
return nullptr;
|
||||
}
|
||||
// Assign the image key to the atlas.
|
||||
atlas->AddUserData(reinterpret_cast<UserDataKey*>(manager),
|
||||
(void*)(uintptr_t)result.value().mHandle,
|
||||
nullptr);
|
||||
// Create a user data notification for when the layer manager is
|
||||
// destroyed so we can clean up any assigned image keys.
|
||||
WRUserData::Assign(manager);
|
||||
}
|
||||
return atlas.forget();
|
||||
}
|
||||
|
||||
static void
|
||||
DrawHexChar(uint32_t aDigit, Float aLeft, Float aTop, DrawTarget& aDrawTarget,
|
||||
SourceSurface* aAtlas, const Color& aColor,
|
||||
const Matrix* aMat = nullptr)
|
||||
{
|
||||
Rect dest(aLeft, aTop, MINIFONT_WIDTH, MINIFONT_HEIGHT);
|
||||
if (aDrawTarget.GetBackendType() == BackendType::WEBRENDER_TEXT) {
|
||||
// For WR, we need to get the image key assigned to the given WR layer manager
|
||||
// for referencing the image.
|
||||
auto* tdt = static_cast<layout::TextDrawTarget*>(&aDrawTarget);
|
||||
auto* manager = tdt->WrLayerManager();
|
||||
wr::ImageKey key = {
|
||||
manager->WrBridge()->GetNamespace(),
|
||||
(uint32_t)(uintptr_t)aAtlas->GetUserData(reinterpret_cast<UserDataKey*>(manager))
|
||||
};
|
||||
// Transform the bounds of the atlas into the given orientation, and then also transform
|
||||
// a small clip rect which will be used to select the given digit from the atlas.
|
||||
Rect bounds(aLeft - aDigit * MINIFONT_WIDTH, aTop, MINIFONT_WIDTH * 16, MINIFONT_HEIGHT);
|
||||
if (aMat) {
|
||||
// Width and height may be negative after the transform, so move the rect
|
||||
// if necessary and fix size.
|
||||
bounds = aMat->TransformRect(bounds);
|
||||
bounds.x += std::min(bounds.width, 0.0f);
|
||||
bounds.y += std::min(bounds.height, 0.0f);
|
||||
bounds.width = fabs(bounds.width);
|
||||
bounds.height = fabs(bounds.height);
|
||||
dest = aMat->TransformRect(dest);
|
||||
dest.x += std::min(dest.width, 0.0f);
|
||||
dest.y += std::min(dest.height, 0.0f);
|
||||
dest.width = fabs(dest.width);
|
||||
dest.height = fabs(dest.height);
|
||||
}
|
||||
// Finally, push the colored image with point filtering.
|
||||
tdt->PushImage(key,
|
||||
wr::ToLayoutRect(bounds),
|
||||
wr::ToLayoutRect(dest),
|
||||
wr::ImageRendering::Pixelated,
|
||||
wr::ToColorF(aColor));
|
||||
} else {
|
||||
// For the normal case, just draw the given digit from the atlas. Point filtering is used
|
||||
// to ensure the mini-font rectangles stay sharp with any scaling. Handle any transparency
|
||||
// here as well.
|
||||
aDrawTarget.DrawSurface(aAtlas,
|
||||
dest,
|
||||
Rect(aDigit * MINIFONT_WIDTH, 0, MINIFONT_WIDTH, MINIFONT_HEIGHT),
|
||||
DrawSurfaceOptions(SamplingFilter::POINT),
|
||||
DrawOptions(aColor.a, CompositionOp::OP_OVER, AntialiasMode::NONE));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gfxFontMissingGlyphs::Purge()
|
||||
{
|
||||
PurgeGlyphAtlas();
|
||||
PurgeWRGlyphAtlas();
|
||||
}
|
||||
|
||||
#else // MOZ_GFX_OPTIMIZE_MOBILE
|
||||
|
||||
void
|
||||
gfxFontMissingGlyphs::Purge()
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
gfxFontMissingGlyphs::Shutdown()
|
||||
{
|
||||
Purge();
|
||||
}
|
||||
#endif // MOZ_GFX_OPTIMIZE_MOBILE
|
||||
|
||||
void
|
||||
gfxFontMissingGlyphs::DrawMissingGlyph(uint32_t aChar,
|
||||
|
@ -228,9 +402,9 @@ gfxFontMissingGlyphs::DrawMissingGlyph(uint32_t aChar,
|
|||
|
||||
// If we're currently drawing with some kind of pattern, we just draw the
|
||||
// missing-glyph data in black.
|
||||
ColorPattern color = aPattern.GetType() == PatternType::COLOR ?
|
||||
static_cast<const ColorPattern&>(aPattern) :
|
||||
ColorPattern(ToDeviceColor(Color(0.f, 0.f, 0.f, 1.f)));
|
||||
Color color = aPattern.GetType() == PatternType::COLOR ?
|
||||
static_cast<const ColorPattern&>(aPattern).mColor :
|
||||
ToDeviceColor(Color(0.f, 0.f, 0.f, 1.f));
|
||||
|
||||
// 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
|
||||
|
@ -242,7 +416,7 @@ gfxFontMissingGlyphs::DrawMissingGlyph(uint32_t aChar,
|
|||
borderRight - borderLeft,
|
||||
rect.Height() - 2.0 * halfBorderWidth);
|
||||
if (!borderStrokeRect.IsEmpty()) {
|
||||
ColorPattern adjustedColor = color;
|
||||
ColorPattern adjustedColor(color);
|
||||
adjustedColor.mColor.a *= BOX_BORDER_OPACITY;
|
||||
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
|
||||
aDrawTarget.FillRect(borderStrokeRect, adjustedColor);
|
||||
|
@ -253,6 +427,14 @@ gfxFontMissingGlyphs::DrawMissingGlyph(uint32_t aChar,
|
|||
}
|
||||
|
||||
#ifndef MOZ_GFX_OPTIMIZE_MOBILE
|
||||
RefPtr<SourceSurface> atlas =
|
||||
aDrawTarget.GetBackendType() == BackendType::WEBRENDER_TEXT ?
|
||||
GetWRGlyphAtlas(aDrawTarget, aMat) :
|
||||
GetGlyphAtlas(color);
|
||||
if (!atlas) {
|
||||
return;
|
||||
}
|
||||
|
||||
Point center = rect.Center();
|
||||
Float halfGap = HEX_CHAR_GAP / 2.f;
|
||||
Float top = -(MINIFONT_HEIGHT + halfGap);
|
||||
|
@ -284,14 +466,10 @@ gfxFontMissingGlyphs::DrawMissingGlyph(uint32_t aChar,
|
|||
rect.Height() >= 2 * MINIFONT_HEIGHT + HEX_CHAR_GAP) {
|
||||
// Draw 4 digits for BMP
|
||||
Float left = -(MINIFONT_WIDTH + halfGap);
|
||||
DrawHexChar((aChar >> 12) & 0xF,
|
||||
Point(left, top), aDrawTarget, color, aMat);
|
||||
DrawHexChar((aChar >> 8) & 0xF,
|
||||
Point(halfGap, top), aDrawTarget, color, aMat);
|
||||
DrawHexChar((aChar >> 4) & 0xF,
|
||||
Point(left, halfGap), aDrawTarget, color, aMat);
|
||||
DrawHexChar(aChar & 0xF,
|
||||
Point(halfGap, halfGap), aDrawTarget, color, aMat);
|
||||
DrawHexChar((aChar >> 12) & 0xF, left, top, aDrawTarget, atlas, color, aMat);
|
||||
DrawHexChar((aChar >> 8) & 0xF, halfGap, top, aDrawTarget, atlas, color, aMat);
|
||||
DrawHexChar((aChar >> 4) & 0xF, left, halfGap, aDrawTarget, atlas, color, aMat);
|
||||
DrawHexChar(aChar & 0xF, halfGap, halfGap, aDrawTarget, atlas, color, aMat);
|
||||
}
|
||||
} else {
|
||||
if (rect.Width() >= 3 * (MINIFONT_WIDTH + HEX_CHAR_GAP) &&
|
||||
|
@ -300,18 +478,12 @@ gfxFontMissingGlyphs::DrawMissingGlyph(uint32_t aChar,
|
|||
Float first = -(MINIFONT_WIDTH * 1.5 + HEX_CHAR_GAP);
|
||||
Float second = -(MINIFONT_WIDTH / 2.0);
|
||||
Float third = (MINIFONT_WIDTH / 2.0 + HEX_CHAR_GAP);
|
||||
DrawHexChar((aChar >> 20) & 0xF,
|
||||
Point(first, top), aDrawTarget, color, aMat);
|
||||
DrawHexChar((aChar >> 16) & 0xF,
|
||||
Point(second, top), aDrawTarget, color, aMat);
|
||||
DrawHexChar((aChar >> 12) & 0xF,
|
||||
Point(third, top), aDrawTarget, color, aMat);
|
||||
DrawHexChar((aChar >> 8) & 0xF,
|
||||
Point(first, halfGap), aDrawTarget, color, aMat);
|
||||
DrawHexChar((aChar >> 4) & 0xF,
|
||||
Point(second, halfGap), aDrawTarget, color, aMat);
|
||||
DrawHexChar(aChar & 0xF,
|
||||
Point(third, halfGap), aDrawTarget, color, aMat);
|
||||
DrawHexChar((aChar >> 20) & 0xF, first, top, aDrawTarget, atlas, color, aMat);
|
||||
DrawHexChar((aChar >> 16) & 0xF, second, top, aDrawTarget, atlas, color, aMat);
|
||||
DrawHexChar((aChar >> 12) & 0xF, third, top, aDrawTarget, atlas, color, aMat);
|
||||
DrawHexChar((aChar >> 8) & 0xF, first, halfGap, aDrawTarget, atlas, color, aMat);
|
||||
DrawHexChar((aChar >> 4) & 0xF, second, halfGap, aDrawTarget, atlas, color, aMat);
|
||||
DrawHexChar(aChar & 0xF, third, halfGap, aDrawTarget, atlas, color, aMat);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,10 @@ public:
|
|||
*/
|
||||
static Float GetDesiredMinWidth(uint32_t aChar,
|
||||
uint32_t aAppUnitsPerDevUnit);
|
||||
|
||||
static void Purge();
|
||||
|
||||
static void Shutdown();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
#include "gfx2DGlue.h"
|
||||
#include "gfxGradientCache.h"
|
||||
#include "gfxUtils.h" // for NextPowerOfTwo
|
||||
#include "gfxFontMissingGlyphs.h"
|
||||
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "nsUnicodeRange.h"
|
||||
|
@ -470,6 +471,7 @@ gfxPlatform::OnMemoryPressure(layers::MemoryPressureReason aWhy)
|
|||
{
|
||||
Factory::PurgeAllCaches();
|
||||
gfxGradientCache::PurgeAllCaches();
|
||||
gfxFontMissingGlyphs::Purge();
|
||||
PurgeSkiaFontCache();
|
||||
PurgeSkiaGPUCache();
|
||||
if (XRE_IsParentProcess()) {
|
||||
|
@ -964,6 +966,7 @@ gfxPlatform::Shutdown()
|
|||
gfxAlphaBoxBlur::ShutdownBlurCache();
|
||||
gfxGraphiteShaper::Shutdown();
|
||||
gfxPlatformFontList::Shutdown();
|
||||
gfxFontMissingGlyphs::Shutdown();
|
||||
ShutdownTileCache();
|
||||
|
||||
// Free the various non-null transforms and loaded profiles
|
||||
|
|
Загрузка…
Ссылка в новой задаче