/* FreeType font driver for Haiku
Copyright (C) 2021 Free Software Foundation, Inc.
This file is part of GNU Emacs.
GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Emacs. If not, see . */
#include
#include "haiku_support.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include FT_FREETYPE_H
#include FT_SIZES_H
#include FT_BITMAP_H
#include FT_IMAGE_H
#include FT_OUTLINE_H
#define FLOAT_FROM_26_6(t) ((float) (t) / 64.0f)
#define DOUBLE_TO_16_16(d) ((FT_Fixed) ((d) * 65536.0))
#define VECTOR_POINT(v) (BPoint (FLOAT_FROM_26_6 ((v)->x), \
FLOAT_FROM_26_6 ((v)->y)))
static int tx;
static int mty;
struct ftbe_shape_cache
{
std::unordered_map shapes;
};
static int
move_to (FT_Vector *to, void *closure)
{
BShape *shape = (BShape *) closure;
return shape->MoveTo (VECTOR_POINT (to)) != B_OK;
}
static int
line_to (FT_Vector *to, void *closure)
{
BShape *shape = (BShape *) closure;
return shape->LineTo (VECTOR_POINT (to)) != B_OK;
}
static int
conic_to (FT_Vector *control, FT_Vector *to, void *closure)
{
BShape *shape = (BShape *) closure;
BPoint pt_0 = shape->CurrentPosition ();
return shape->BezierTo
(BPoint (pt_0.x + 2.0f / 3.0f * (FLOAT_FROM_26_6 (control->x) - pt_0.x),
pt_0.y + 2.0f / 3.0f * (FLOAT_FROM_26_6 (control->y) - pt_0.y)),
BPoint (FLOAT_FROM_26_6 (to->x) + 2.0f / 3.0f * (FLOAT_FROM_26_6 (control->x) -
FLOAT_FROM_26_6 (to->x)),
FLOAT_FROM_26_6 (to->y) + 2.0f / 3.0f * (FLOAT_FROM_26_6 (control->y) -
FLOAT_FROM_26_6 (to->y))),
VECTOR_POINT (to)) != B_OK;
}
static int
cubic_to (FT_Vector *control1, FT_Vector *control2,
FT_Vector *to, void *closure)
{
BShape *shape = (BShape *) closure;
return shape->BezierTo (VECTOR_POINT (control1),
VECTOR_POINT (control2),
VECTOR_POINT (to)) != B_OK;
}
static int
digest_outline (FT_Outline *outline, FT_Face face, BShape *shape)
{
static const FT_Matrix invert_y =
{
DOUBLE_TO_16_16 (1.0), 0,
0, DOUBLE_TO_16_16 (-1.0),
};
static const FT_Outline_Funcs outline_funcs =
{
(FT_Outline_MoveToFunc) move_to,
(FT_Outline_LineToFunc) line_to,
(FT_Outline_ConicToFunc) conic_to,
(FT_Outline_CubicToFunc) cubic_to,
0, 0
};
FT_Outline_Translate (outline, tx * 64.0, -mty * 64.0);
FT_Outline_Transform (outline, &invert_y);
if (FT_Outline_Decompose (outline, &outline_funcs, shape) != FT_Err_Ok)
return 1;
if (shape->Close () != B_OK)
return 1;
return 0;
}
static void
digest_color_bitmap_bgra (FT_Bitmap *bitmap, BBitmap *be_bitmap,
BRegion *cr)
{
if (be_bitmap->ColorSpace () != B_RGBA32)
abort ();
uint8_t *_src = bitmap->buffer;
uint8_t *_dst = (uint8_t *) be_bitmap->Bits ();
for (int y = 0; y < bitmap->rows; ++y)
{
uint8_t *src = _src + bitmap->pitch * y;
uint8_t *dst = _dst + be_bitmap->BytesPerRow () * y;
for (int x = 0; x < bitmap->width; ++x)
{
uint8_t b = *src++, g = *src++, r = *src++, a = *src++;
*dst++ = r;
*dst++ = g;
*dst++ = b;
*dst++ = cr->Contains (BPoint (x, y)) ? a : 0;
}
}
}
extern "C"
{
extern void emacs_abort (void);
}
extern void
be_free_ft_shape_cache (void *c)
{
for (const std::pair &pair :
((struct ftbe_shape_cache *) c)->shapes)
delete pair.second;
delete (struct ftbe_shape_cache *) c;
}
extern void *
be_make_ft_shape_cache (void)
{
return new struct ftbe_shape_cache;
}
extern void
BView_FT_render_glyphs (FT_Face face, unsigned int *codes,
int len, uint32_t color, int x, int y,
void *view, void *ft_shape_cache, int flags)
{
FT_Error error = FT_Err_Ok;
BView *vw = (BView *) find_appropriate_view_for_draw (view);
struct ftbe_shape_cache *c = (struct ftbe_shape_cache *) ft_shape_cache;
BShape gshape;
gshape.Clear ();
tx = 0, mty = 0;
if (len >= 25)
{
vw->MovePenTo (x, y);
x = 0, y = 0;
}
BView_SetHighColor (view, color);
for (int i = 0; i < len; ++i)
{
error = FT_Load_Glyph (face, codes[i], flags);
if (error != FT_Err_Ok)
continue;
if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
{
BShape *shape;
if (len < 25)
shape = c->shapes[codes[i]];
if (len >= 25)
tx = x, mty = y;
if (!shape || len >= 25)
{
if (len < 25)
{
shape = new BShape ();
shape->Clear ();
}
digest_outline (&face->glyph->outline, face,
len >= 25 ? &gshape : shape);
if (len < 25)
c->shapes[codes[i]] = shape;
}
if (len < 25)
{
vw->MovePenTo (x, y);
vw->FillShape (shape);
}
}
else
{
error = FT_Render_Glyph (face->glyph, FT_RENDER_MODE_NORMAL);
if (error != FT_Err_Ok)
continue;
if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA)
{
BBitmap bm (BRect (0, 0, face->glyph->bitmap.width,
face->glyph->bitmap.rows),
B_RGBA32);
BRegion cr;
vw->GetClippingRegion (&cr);
digest_color_bitmap_bgra (&face->glyph->bitmap, &bm, &cr);
vw->SetDrawingMode (B_OP_OVER);
vw->MovePenTo (x + face->glyph->bitmap_left,
y - face->glyph->bitmap_top);
vw->DrawBitmap (&bm);
}
}
x += face->glyph->advance.x >> 6;
y += face->glyph->advance.y >> 6;
}
if (len >= 25)
vw->FillShape (&gshape);
}