app_server: add B_UNDERSCORE_FACE support
There was some confusion (and a TODO indicating it) in ServerFont.cpp, because the notion of "font face" from the Be API is partially implemented using different font manager styles (bold, italic, etc), and partially by keeping flags in a separate variable for drawing extra things or modifying the drawing (underscore, strikeout, ...). The implementation did not actually preserve the extra flags, and so the underscore face attribute was lost. Implement the actual underlining of the text in AGGTextRenderer. This implementation is a naive one so far. In particular there are the following limitations: 1. Line is drawn over the text - no nice gaps for descents. Ideally, the line should not touch the letter descents, and leave some space around them. I don't know how to retrieve the contour - it appears to me this might require bigger refactoring of this code. I have left in my experiments commented out in the code. 2. If the text run ends with whitespace, the whitespace is not underlined as it should. In particular if another text run is drawn next to it and it's expected that the underline is continuous between the two. Change-Id: I8d78b8e1eceddff0a7d98e5a49659e7b03fd89a0 Reviewed-on: https://review.haiku-os.org/c/haiku/+/3041 Reviewed-by: Kacper Kasper <kacperkasper@gmail.com> Reviewed-by: Adrien Destugues <pulkomandy@gmail.com> Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
This commit is contained in:
parent
627fb72d50
commit
ef83008e79
@ -192,6 +192,8 @@ ServerFont::operator=(const ServerFont& font)
|
||||
|
||||
SetStyle(font.fStyle);
|
||||
|
||||
fFace = font.fFace;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -252,7 +254,7 @@ ServerFont::SetStyle(FontStyle* style)
|
||||
if (style && style != fStyle) {
|
||||
fStyle.SetTo(style, false);
|
||||
|
||||
fFace = fStyle->Face();
|
||||
fFace = fStyle->PreservedFace(fFace);
|
||||
fDirection = fStyle->Direction();
|
||||
}
|
||||
}
|
||||
@ -304,10 +306,8 @@ ServerFont::SetFamilyAndStyle(uint32 fontID)
|
||||
status_t
|
||||
ServerFont::SetFace(uint16 face)
|
||||
{
|
||||
// TODO: This needs further investigation. The face variable is actually
|
||||
// flags, but some of them are not enforcable at the same time. Also don't
|
||||
// confuse the Be API "face" with the Freetype face, which is just an
|
||||
// index in case a single font file exports multiple font faces. The
|
||||
// Don't confuse the Be API "face" with the Freetype face, which is just
|
||||
// an index in case a single font file exports multiple font faces. The
|
||||
// FontStyle class takes care of mapping the font style name to the Be
|
||||
// API face flags in FontStyle::_TranslateStyleToFace().
|
||||
|
||||
@ -319,7 +319,7 @@ ServerFont::SetFace(uint16 face)
|
||||
style.SetTo(gFontManager->GetStyleByIndex(familyID, i), false);
|
||||
if (style == NULL)
|
||||
break;
|
||||
if (style->Face() == face)
|
||||
if (style->PreservedFace(face) == face)
|
||||
break;
|
||||
else
|
||||
style = NULL;
|
||||
@ -331,6 +331,7 @@ ServerFont::SetFace(uint16 face)
|
||||
if (!style)
|
||||
return B_ERROR;
|
||||
|
||||
fFace = face;
|
||||
SetStyle(style);
|
||||
|
||||
return B_OK;
|
||||
|
@ -9,7 +9,10 @@
|
||||
#include <agg_basics.h>
|
||||
#include <agg_bounding_rect.h>
|
||||
#include <agg_conv_segmentator.h>
|
||||
#include <agg_conv_stroke.h>
|
||||
#include <agg_conv_transform.h>
|
||||
#include <agg_path_storage.h>
|
||||
#include <agg_scanline_boolean_algebra.h>
|
||||
#include <agg_trans_affine.h>
|
||||
|
||||
#include <math.h>
|
||||
@ -19,11 +22,6 @@
|
||||
|
||||
#define SHOW_GLYPH_BOUNDS 0
|
||||
|
||||
#if SHOW_GLYPH_BOUNDS
|
||||
# include <agg_conv_stroke.h>
|
||||
# include <agg_path_storage.h>
|
||||
#endif
|
||||
|
||||
#include "GlobalSubpixelSettings.h"
|
||||
#include "GlyphLayoutEngine.h"
|
||||
#include "IntRect.h"
|
||||
@ -121,7 +119,7 @@ typedef agg::conv_transform<FontCacheEntry::ContourConverter, Transformable>
|
||||
class AGGTextRenderer::StringRenderer {
|
||||
public:
|
||||
StringRenderer(const IntRect& clippingFrame, bool dryRun,
|
||||
bool subpixelAntiAliased,
|
||||
bool subpixelAntiAliased, bool underscore,
|
||||
FontCacheEntry::TransformedOutline& transformedGlyph,
|
||||
FontCacheEntry::TransformedContourOutline& transformedContour,
|
||||
const Transformable& transform,
|
||||
@ -135,6 +133,7 @@ public:
|
||||
fDryRun(dryRun),
|
||||
fSubpixelAntiAliased(subpixelAntiAliased),
|
||||
fVector(false),
|
||||
fUnderscore(underscore),
|
||||
fBounds(INT32_MAX, INT32_MAX, INT32_MIN, INT32_MIN),
|
||||
fNextCharPos(nextCharPos),
|
||||
|
||||
@ -171,6 +170,49 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
if (fUnderscore && !fDryRun) {
|
||||
agg::path_storage p;
|
||||
IntRect b = fBounds;
|
||||
b.bottom = (int)y;
|
||||
b.OffsetBy(fTransformOffset);
|
||||
p.move_to(b.left + 0.5, b.bottom + 2.5);
|
||||
p.line_to(b.right + 0.5, b.bottom + 2.5);
|
||||
p.close_polygon();
|
||||
agg::conv_stroke<agg::path_storage> ps(p);
|
||||
ps.width(fRenderer.fFont.Size() / 12.0f);
|
||||
if (fRenderer.fMaskedScanline != NULL) {
|
||||
fRenderer.fRasterizer.add_path(ps);
|
||||
agg::render_scanlines(fRenderer.fRasterizer,
|
||||
*fRenderer.fMaskedScanline, fRenderer.fSolidRenderer);
|
||||
} else if (fSubpixelAntiAliased) {
|
||||
fRenderer.fSubpixRasterizer.add_path(ps);
|
||||
agg::render_scanlines(fRenderer.fSubpixRasterizer,
|
||||
fRenderer.fSubpixScanline, fRenderer.fSubpixRenderer);
|
||||
} else {
|
||||
/*
|
||||
scanline_unpacked_type sl1;
|
||||
scanline_unpacked_type sl2;
|
||||
|
||||
rasterizer_type ras1;
|
||||
rasterizer_type ras2;
|
||||
|
||||
ras1.add_path(ps);
|
||||
ras2.add_path(fTransformedContour);
|
||||
|
||||
agg::render_scanlines(ras1,
|
||||
sl1, fRenderer.fSolidRenderer);
|
||||
agg::render_scanlines(ras2,
|
||||
sl2, fRenderer.fSolidRenderer);
|
||||
|
||||
agg::sbool_combine_shapes_aa(agg::sbool_a_minus_b,
|
||||
ras1, ras2, sl1, sl2, fRenderer.fScanline, fRenderer.fSolidRenderer);
|
||||
*/
|
||||
fRenderer.fRasterizer.add_path(ps);
|
||||
agg::render_scanlines(fRenderer.fRasterizer,
|
||||
fRenderer.fScanline, fRenderer.fSolidRenderer);
|
||||
}
|
||||
}
|
||||
|
||||
if (fNextCharPos) {
|
||||
fNextCharPos->x = x;
|
||||
fNextCharPos->y = y;
|
||||
@ -322,6 +364,7 @@ private:
|
||||
bool fDryRun;
|
||||
bool fSubpixelAntiAliased;
|
||||
bool fVector;
|
||||
bool fUnderscore;
|
||||
IntRect fBounds;
|
||||
BPoint* fNextCharPos;
|
||||
|
||||
@ -358,8 +401,10 @@ AGGTextRenderer::RenderString(const char* string, uint32 length,
|
||||
transform.Transform(&transformOffset);
|
||||
IntRect clippingIntFrame(clippingFrame);
|
||||
|
||||
bool underscore = fFont.Face() & B_UNDERSCORE_FACE;
|
||||
|
||||
StringRenderer renderer(clippingIntFrame, dryRun,
|
||||
gSubpixelAntialiasing && fAntialias,
|
||||
gSubpixelAntialiasing && fAntialias, underscore,
|
||||
transformedOutline, transformedContourOutline,
|
||||
transform, transformOffset, nextCharPos, *this);
|
||||
|
||||
@ -395,8 +440,10 @@ AGGTextRenderer::RenderString(const char* string, uint32 length,
|
||||
transform.Transform(&transformOffset);
|
||||
IntRect clippingIntFrame(clippingFrame);
|
||||
|
||||
bool underscore = fFont.Face() & B_UNDERSCORE_FACE;
|
||||
|
||||
StringRenderer renderer(clippingIntFrame, dryRun,
|
||||
gSubpixelAntialiasing && fAntialias,
|
||||
gSubpixelAntialiasing && fAntialias, underscore,
|
||||
transformedOutline, transformedContourOutline,
|
||||
transform, transformOffset, nextCharPos, *this);
|
||||
|
||||
|
@ -260,9 +260,12 @@ FontFamily::GetStyleByID(uint16 id) const
|
||||
FontStyle*
|
||||
FontFamily::GetStyleMatchingFace(uint16 face) const
|
||||
{
|
||||
// TODO: support other faces (strike through, underlined, outlines...)
|
||||
// Other face flags do not impact the font selection (they are applied
|
||||
// during drawing)
|
||||
face &= B_BOLD_FACE | B_ITALIC_FACE | B_REGULAR_FACE | B_CONDENSED_FACE
|
||||
| B_LIGHT_FACE | B_HEAVY_FACE;
|
||||
if (face == 0)
|
||||
face = B_REGULAR_FACE;
|
||||
|
||||
int32 count = fStyles.CountItems();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
|
@ -188,7 +188,8 @@ uint16
|
||||
FontStyle::PreservedFace(uint16 face) const
|
||||
{
|
||||
// TODO: make this better
|
||||
face &= ~(B_REGULAR_FACE | B_BOLD_FACE | B_ITALIC_FACE);
|
||||
face &= ~(B_REGULAR_FACE | B_BOLD_FACE | B_ITALIC_FACE | B_CONDENSED_FACE
|
||||
| B_LIGHT_FACE | B_HEAVY_FACE);
|
||||
face |= Face();
|
||||
|
||||
return face;
|
||||
|
Loading…
x
Reference in New Issue
Block a user