2007-08-02 23:10:38 +04:00
|
|
|
/*
|
|
|
|
* Copyright 2007, Haiku. All rights reserved.
|
|
|
|
* Distributed under the terms of the MIT License.
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Stephan Aßmus <superstippi@gmx.de>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef GLYPH_LAYOUT_ENGINE_H
|
|
|
|
#define GLYPH_LAYOUT_ENGINE_H
|
|
|
|
|
|
|
|
#include "utf8_functions.h"
|
|
|
|
|
|
|
|
#include "FontCache.h"
|
|
|
|
#include "FontCacheEntry.h"
|
|
|
|
#include "ServerFont.h"
|
|
|
|
|
2007-08-10 01:53:36 +04:00
|
|
|
#include <ctype.h>
|
2007-08-02 23:10:38 +04:00
|
|
|
|
* after my last changes to font rendering, it was about 15% slower than
before (although there should be much less lock contention)
* with this change, there is quite a bit of cleanup, text drawing is now
about 20% faster than before the original changes to font caching,
mostly due to turning off the kerning feature, which at the moment
gives absolutely no benefit. The correct way of doing it might be to
use kerning depending on the provided glyph spacing mode
* removed fPenLocation from Painter, the usage should be more correct now,
since it is now consistently applied before the coordinate transformation
from view to screen (also for DrawShape() now, before any view scaling
and origin offset)
* Painter no longer has it's own instance of a ServerFont, instead it uses
its AGGTextRenderer instance, which was per Painter again after the
last change, and not global anymore, made _UpdateFont() useless
* When using GlyphLayoutEngine, it supports a second pass with the same
FontCacheEntry through the introduction of a FontCacheReference. This
speeds up DrawString a little, since it needs to calculate the bounding
box for the string, and then draw the string in a second pass. This is
now done with only one FontCacheEntry lookup
* I also tried to optimize the on-the-fly conversion of UTF8->CharCode away,
since it was done four times per DrawString, but surprisingly, it proofed
to be a slight slowdown.
* introduced a shortcut in DrawingEngine::DrawString() which avoids
calculating the bounding box, we are now a tiny bit faster to figure
out that we don't need to draw any string than Dano
In the test environment (drawing to offscreen bitmap and blitting to
screen eventually), text rendering is now about 3.7 times _faster_ than Dano
text rendering (directly to screen), for untransformed text. Unfortunately
I cannot test on the same machine in accelerant using version of the test
environment.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21822 a95241bf-73f2-0310-859d-f6bbb57e9c96
2007-08-04 15:37:16 +04:00
|
|
|
class FontCacheReference {
|
|
|
|
public:
|
|
|
|
FontCacheReference()
|
|
|
|
: fCacheEntry(NULL)
|
|
|
|
, fWriteLocked(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
~FontCacheReference()
|
|
|
|
{
|
|
|
|
if (fCacheEntry) {
|
|
|
|
if (fWriteLocked)
|
|
|
|
fCacheEntry->WriteUnlock();
|
|
|
|
else
|
|
|
|
fCacheEntry->ReadUnlock();
|
|
|
|
|
|
|
|
FontCache::Default()->Recycle(
|
|
|
|
fCacheEntry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void SetTo(FontCacheEntry* entry,
|
|
|
|
bool writeLocked)
|
|
|
|
{
|
|
|
|
fCacheEntry = entry;
|
|
|
|
fWriteLocked = writeLocked;
|
|
|
|
}
|
|
|
|
inline FontCacheEntry* Entry() const
|
|
|
|
{ return fCacheEntry; }
|
|
|
|
inline bool WriteLocked() const
|
|
|
|
{ return fWriteLocked; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
FontCacheEntry* fCacheEntry;
|
|
|
|
bool fWriteLocked;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2007-08-02 23:10:38 +04:00
|
|
|
class GlyphLayoutEngine {
|
|
|
|
public:
|
|
|
|
|
|
|
|
template<class GlyphConsumer>
|
|
|
|
static bool LayoutGlyphs(GlyphConsumer& consumer,
|
|
|
|
const ServerFont& font,
|
|
|
|
const char* utf8String,
|
|
|
|
int32 length,
|
|
|
|
const escapement_delta* delta = NULL,
|
|
|
|
bool kerning = true,
|
* after my last changes to font rendering, it was about 15% slower than
before (although there should be much less lock contention)
* with this change, there is quite a bit of cleanup, text drawing is now
about 20% faster than before the original changes to font caching,
mostly due to turning off the kerning feature, which at the moment
gives absolutely no benefit. The correct way of doing it might be to
use kerning depending on the provided glyph spacing mode
* removed fPenLocation from Painter, the usage should be more correct now,
since it is now consistently applied before the coordinate transformation
from view to screen (also for DrawShape() now, before any view scaling
and origin offset)
* Painter no longer has it's own instance of a ServerFont, instead it uses
its AGGTextRenderer instance, which was per Painter again after the
last change, and not global anymore, made _UpdateFont() useless
* When using GlyphLayoutEngine, it supports a second pass with the same
FontCacheEntry through the introduction of a FontCacheReference. This
speeds up DrawString a little, since it needs to calculate the bounding
box for the string, and then draw the string in a second pass. This is
now done with only one FontCacheEntry lookup
* I also tried to optimize the on-the-fly conversion of UTF8->CharCode away,
since it was done four times per DrawString, but surprisingly, it proofed
to be a slight slowdown.
* introduced a shortcut in DrawingEngine::DrawString() which avoids
calculating the bounding box, we are now a tiny bit faster to figure
out that we don't need to draw any string than Dano
In the test environment (drawing to offscreen bitmap and blitting to
screen eventually), text rendering is now about 3.7 times _faster_ than Dano
text rendering (directly to screen), for untransformed text. Unfortunately
I cannot test on the same machine in accelerant using version of the test
environment.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21822 a95241bf-73f2-0310-859d-f6bbb57e9c96
2007-08-04 15:37:16 +04:00
|
|
|
uint8 spacing = B_BITMAP_SPACING,
|
|
|
|
FontCacheReference* cacheReference = NULL);
|
2007-08-02 23:10:38 +04:00
|
|
|
|
2007-08-03 05:11:27 +04:00
|
|
|
static bool IsWhiteSpace(uint32 glyphCode);
|
|
|
|
|
2007-08-02 23:10:38 +04:00
|
|
|
private:
|
|
|
|
GlyphLayoutEngine();
|
|
|
|
virtual ~GlyphLayoutEngine();
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2007-08-03 05:11:27 +04:00
|
|
|
// IsWhiteSpace
|
2007-08-02 23:10:38 +04:00
|
|
|
inline bool
|
2007-08-03 05:11:27 +04:00
|
|
|
GlyphLayoutEngine::IsWhiteSpace(uint32 charCode)
|
2007-08-02 23:10:38 +04:00
|
|
|
{
|
|
|
|
switch (charCode) {
|
|
|
|
case 0x0009: /* tab */
|
|
|
|
case 0x000b: /* vertical tab */
|
|
|
|
case 0x000c: /* form feed */
|
|
|
|
case 0x0020: /* space */
|
|
|
|
case 0x00a0: /* non breaking space */
|
|
|
|
case 0x000a: /* line feed */
|
|
|
|
case 0x000d: /* carriage return */
|
|
|
|
case 0x2028: /* line separator */
|
|
|
|
case 0x2029: /* paragraph separator */
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// LayoutGlyphs
|
|
|
|
template<class GlyphConsumer>
|
|
|
|
inline bool
|
|
|
|
GlyphLayoutEngine::LayoutGlyphs(GlyphConsumer& consumer,
|
|
|
|
const ServerFont& font,
|
|
|
|
const char* utf8String, int32 length,
|
* after my last changes to font rendering, it was about 15% slower than
before (although there should be much less lock contention)
* with this change, there is quite a bit of cleanup, text drawing is now
about 20% faster than before the original changes to font caching,
mostly due to turning off the kerning feature, which at the moment
gives absolutely no benefit. The correct way of doing it might be to
use kerning depending on the provided glyph spacing mode
* removed fPenLocation from Painter, the usage should be more correct now,
since it is now consistently applied before the coordinate transformation
from view to screen (also for DrawShape() now, before any view scaling
and origin offset)
* Painter no longer has it's own instance of a ServerFont, instead it uses
its AGGTextRenderer instance, which was per Painter again after the
last change, and not global anymore, made _UpdateFont() useless
* When using GlyphLayoutEngine, it supports a second pass with the same
FontCacheEntry through the introduction of a FontCacheReference. This
speeds up DrawString a little, since it needs to calculate the bounding
box for the string, and then draw the string in a second pass. This is
now done with only one FontCacheEntry lookup
* I also tried to optimize the on-the-fly conversion of UTF8->CharCode away,
since it was done four times per DrawString, but surprisingly, it proofed
to be a slight slowdown.
* introduced a shortcut in DrawingEngine::DrawString() which avoids
calculating the bounding box, we are now a tiny bit faster to figure
out that we don't need to draw any string than Dano
In the test environment (drawing to offscreen bitmap and blitting to
screen eventually), text rendering is now about 3.7 times _faster_ than Dano
text rendering (directly to screen), for untransformed text. Unfortunately
I cannot test on the same machine in accelerant using version of the test
environment.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21822 a95241bf-73f2-0310-859d-f6bbb57e9c96
2007-08-04 15:37:16 +04:00
|
|
|
const escapement_delta* delta, bool kerning, uint8 spacing,
|
|
|
|
FontCacheReference* cacheReference)
|
2007-08-02 23:10:38 +04:00
|
|
|
{
|
2007-08-03 05:11:27 +04:00
|
|
|
// TODO: implement spacing modes
|
2007-08-02 23:10:38 +04:00
|
|
|
|
* after my last changes to font rendering, it was about 15% slower than
before (although there should be much less lock contention)
* with this change, there is quite a bit of cleanup, text drawing is now
about 20% faster than before the original changes to font caching,
mostly due to turning off the kerning feature, which at the moment
gives absolutely no benefit. The correct way of doing it might be to
use kerning depending on the provided glyph spacing mode
* removed fPenLocation from Painter, the usage should be more correct now,
since it is now consistently applied before the coordinate transformation
from view to screen (also for DrawShape() now, before any view scaling
and origin offset)
* Painter no longer has it's own instance of a ServerFont, instead it uses
its AGGTextRenderer instance, which was per Painter again after the
last change, and not global anymore, made _UpdateFont() useless
* When using GlyphLayoutEngine, it supports a second pass with the same
FontCacheEntry through the introduction of a FontCacheReference. This
speeds up DrawString a little, since it needs to calculate the bounding
box for the string, and then draw the string in a second pass. This is
now done with only one FontCacheEntry lookup
* I also tried to optimize the on-the-fly conversion of UTF8->CharCode away,
since it was done four times per DrawString, but surprisingly, it proofed
to be a slight slowdown.
* introduced a shortcut in DrawingEngine::DrawString() which avoids
calculating the bounding box, we are now a tiny bit faster to figure
out that we don't need to draw any string than Dano
In the test environment (drawing to offscreen bitmap and blitting to
screen eventually), text rendering is now about 3.7 times _faster_ than Dano
text rendering (directly to screen), for untransformed text. Unfortunately
I cannot test on the same machine in accelerant using version of the test
environment.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21822 a95241bf-73f2-0310-859d-f6bbb57e9c96
2007-08-04 15:37:16 +04:00
|
|
|
FontCacheEntry* entry = NULL;
|
|
|
|
bool needsWriteLock = false;
|
|
|
|
if (cacheReference) {
|
|
|
|
entry = cacheReference->Entry();
|
|
|
|
needsWriteLock = cacheReference->WriteLocked();
|
2007-08-02 23:10:38 +04:00
|
|
|
}
|
|
|
|
|
* after my last changes to font rendering, it was about 15% slower than
before (although there should be much less lock contention)
* with this change, there is quite a bit of cleanup, text drawing is now
about 20% faster than before the original changes to font caching,
mostly due to turning off the kerning feature, which at the moment
gives absolutely no benefit. The correct way of doing it might be to
use kerning depending on the provided glyph spacing mode
* removed fPenLocation from Painter, the usage should be more correct now,
since it is now consistently applied before the coordinate transformation
from view to screen (also for DrawShape() now, before any view scaling
and origin offset)
* Painter no longer has it's own instance of a ServerFont, instead it uses
its AGGTextRenderer instance, which was per Painter again after the
last change, and not global anymore, made _UpdateFont() useless
* When using GlyphLayoutEngine, it supports a second pass with the same
FontCacheEntry through the introduction of a FontCacheReference. This
speeds up DrawString a little, since it needs to calculate the bounding
box for the string, and then draw the string in a second pass. This is
now done with only one FontCacheEntry lookup
* I also tried to optimize the on-the-fly conversion of UTF8->CharCode away,
since it was done four times per DrawString, but surprisingly, it proofed
to be a slight slowdown.
* introduced a shortcut in DrawingEngine::DrawString() which avoids
calculating the bounding box, we are now a tiny bit faster to figure
out that we don't need to draw any string than Dano
In the test environment (drawing to offscreen bitmap and blitting to
screen eventually), text rendering is now about 3.7 times _faster_ than Dano
text rendering (directly to screen), for untransformed text. Unfortunately
I cannot test on the same machine in accelerant using version of the test
environment.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21822 a95241bf-73f2-0310-859d-f6bbb57e9c96
2007-08-04 15:37:16 +04:00
|
|
|
if (!entry) {
|
|
|
|
FontCache* cache = FontCache::Default();
|
|
|
|
entry = cache->FontCacheEntryFor(font);
|
|
|
|
|
|
|
|
if (!entry || !entry->ReadLock()) {
|
2007-08-02 23:10:38 +04:00
|
|
|
cache->Recycle(entry);
|
|
|
|
return false;
|
|
|
|
}
|
* after my last changes to font rendering, it was about 15% slower than
before (although there should be much less lock contention)
* with this change, there is quite a bit of cleanup, text drawing is now
about 20% faster than before the original changes to font caching,
mostly due to turning off the kerning feature, which at the moment
gives absolutely no benefit. The correct way of doing it might be to
use kerning depending on the provided glyph spacing mode
* removed fPenLocation from Painter, the usage should be more correct now,
since it is now consistently applied before the coordinate transformation
from view to screen (also for DrawShape() now, before any view scaling
and origin offset)
* Painter no longer has it's own instance of a ServerFont, instead it uses
its AGGTextRenderer instance, which was per Painter again after the
last change, and not global anymore, made _UpdateFont() useless
* When using GlyphLayoutEngine, it supports a second pass with the same
FontCacheEntry through the introduction of a FontCacheReference. This
speeds up DrawString a little, since it needs to calculate the bounding
box for the string, and then draw the string in a second pass. This is
now done with only one FontCacheEntry lookup
* I also tried to optimize the on-the-fly conversion of UTF8->CharCode away,
since it was done four times per DrawString, but surprisingly, it proofed
to be a slight slowdown.
* introduced a shortcut in DrawingEngine::DrawString() which avoids
calculating the bounding box, we are now a tiny bit faster to figure
out that we don't need to draw any string than Dano
In the test environment (drawing to offscreen bitmap and blitting to
screen eventually), text rendering is now about 3.7 times _faster_ than Dano
text rendering (directly to screen), for untransformed text. Unfortunately
I cannot test on the same machine in accelerant using version of the test
environment.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21822 a95241bf-73f2-0310-859d-f6bbb57e9c96
2007-08-04 15:37:16 +04:00
|
|
|
|
|
|
|
needsWriteLock = !entry->HasGlyphs(utf8String, length);
|
|
|
|
|
|
|
|
if (needsWriteLock) {
|
|
|
|
entry->ReadUnlock();
|
|
|
|
if (!entry->WriteLock()) {
|
|
|
|
cache->Recycle(entry);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // else the entry was already used and is still locked
|
2007-08-02 23:10:38 +04:00
|
|
|
|
|
|
|
consumer.Start();
|
|
|
|
|
|
|
|
double x = 0.0;
|
|
|
|
double y = 0.0;
|
|
|
|
|
|
|
|
double advanceX = 0.0;
|
|
|
|
double advanceY = 0.0;
|
|
|
|
|
|
|
|
uint32 lastCharCode = 0;
|
|
|
|
uint32 charCode;
|
|
|
|
int32 index = 0;
|
|
|
|
const char* start = utf8String;
|
|
|
|
while ((charCode = UTF8ToCharCode(&utf8String))) {
|
|
|
|
|
|
|
|
const GlyphCache* glyph = entry->Glyph(charCode);
|
|
|
|
if (glyph == NULL) {
|
|
|
|
fprintf(stderr, "failed to load glyph for 0x%04lx (%c)\n", charCode,
|
|
|
|
isprint(charCode) ? (char)charCode : '-');
|
|
|
|
|
|
|
|
consumer.ConsumeEmptyGlyph(index, charCode, x, y);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
* after my last changes to font rendering, it was about 15% slower than
before (although there should be much less lock contention)
* with this change, there is quite a bit of cleanup, text drawing is now
about 20% faster than before the original changes to font caching,
mostly due to turning off the kerning feature, which at the moment
gives absolutely no benefit. The correct way of doing it might be to
use kerning depending on the provided glyph spacing mode
* removed fPenLocation from Painter, the usage should be more correct now,
since it is now consistently applied before the coordinate transformation
from view to screen (also for DrawShape() now, before any view scaling
and origin offset)
* Painter no longer has it's own instance of a ServerFont, instead it uses
its AGGTextRenderer instance, which was per Painter again after the
last change, and not global anymore, made _UpdateFont() useless
* When using GlyphLayoutEngine, it supports a second pass with the same
FontCacheEntry through the introduction of a FontCacheReference. This
speeds up DrawString a little, since it needs to calculate the bounding
box for the string, and then draw the string in a second pass. This is
now done with only one FontCacheEntry lookup
* I also tried to optimize the on-the-fly conversion of UTF8->CharCode away,
since it was done four times per DrawString, but surprisingly, it proofed
to be a slight slowdown.
* introduced a shortcut in DrawingEngine::DrawString() which avoids
calculating the bounding box, we are now a tiny bit faster to figure
out that we don't need to draw any string than Dano
In the test environment (drawing to offscreen bitmap and blitting to
screen eventually), text rendering is now about 3.7 times _faster_ than Dano
text rendering (directly to screen), for untransformed text. Unfortunately
I cannot test on the same machine in accelerant using version of the test
environment.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21822 a95241bf-73f2-0310-859d-f6bbb57e9c96
2007-08-04 15:37:16 +04:00
|
|
|
// if (kerning)
|
|
|
|
// entry->GetKerning(lastCharCode, charCode, &advanceX, &advanceY);
|
2007-08-02 23:10:38 +04:00
|
|
|
|
|
|
|
x += advanceX;
|
|
|
|
y += advanceY;
|
|
|
|
|
|
|
|
if (delta)
|
2007-08-03 05:11:27 +04:00
|
|
|
x += IsWhiteSpace(charCode) ? delta->space : delta->nonspace;
|
2007-08-02 23:10:38 +04:00
|
|
|
|
|
|
|
if (!consumer.ConsumeGlyph(index, charCode, glyph, entry, x, y))
|
|
|
|
break;
|
|
|
|
|
|
|
|
// increment pen position
|
|
|
|
advanceX = glyph->advance_x;
|
|
|
|
advanceY = glyph->advance_y;
|
|
|
|
|
|
|
|
lastCharCode = charCode;
|
|
|
|
index++;
|
|
|
|
if (utf8String - start + 1 > length)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
x += advanceX;
|
|
|
|
y += advanceY;
|
|
|
|
consumer.Finish(x, y);
|
|
|
|
|
* after my last changes to font rendering, it was about 15% slower than
before (although there should be much less lock contention)
* with this change, there is quite a bit of cleanup, text drawing is now
about 20% faster than before the original changes to font caching,
mostly due to turning off the kerning feature, which at the moment
gives absolutely no benefit. The correct way of doing it might be to
use kerning depending on the provided glyph spacing mode
* removed fPenLocation from Painter, the usage should be more correct now,
since it is now consistently applied before the coordinate transformation
from view to screen (also for DrawShape() now, before any view scaling
and origin offset)
* Painter no longer has it's own instance of a ServerFont, instead it uses
its AGGTextRenderer instance, which was per Painter again after the
last change, and not global anymore, made _UpdateFont() useless
* When using GlyphLayoutEngine, it supports a second pass with the same
FontCacheEntry through the introduction of a FontCacheReference. This
speeds up DrawString a little, since it needs to calculate the bounding
box for the string, and then draw the string in a second pass. This is
now done with only one FontCacheEntry lookup
* I also tried to optimize the on-the-fly conversion of UTF8->CharCode away,
since it was done four times per DrawString, but surprisingly, it proofed
to be a slight slowdown.
* introduced a shortcut in DrawingEngine::DrawString() which avoids
calculating the bounding box, we are now a tiny bit faster to figure
out that we don't need to draw any string than Dano
In the test environment (drawing to offscreen bitmap and blitting to
screen eventually), text rendering is now about 3.7 times _faster_ than Dano
text rendering (directly to screen), for untransformed text. Unfortunately
I cannot test on the same machine in accelerant using version of the test
environment.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21822 a95241bf-73f2-0310-859d-f6bbb57e9c96
2007-08-04 15:37:16 +04:00
|
|
|
if (!cacheReference) {
|
|
|
|
if (needsWriteLock)
|
|
|
|
entry->WriteUnlock();
|
|
|
|
else
|
|
|
|
entry->ReadUnlock();
|
|
|
|
|
|
|
|
FontCache::Default()->Recycle(entry);
|
|
|
|
} else {
|
|
|
|
// the reference will take care of locking
|
|
|
|
if (!cacheReference->Entry())
|
|
|
|
cacheReference->SetTo(entry, needsWriteLock);
|
|
|
|
}
|
2007-08-02 23:10:38 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endif // GLYPH_LAYOUT_ENGINE_H
|