Text drawing is working. Refcounted fonts working ok

This commit is contained in:
Vadim Lopatin 2014-03-04 16:39:16 +04:00
parent b8f8f8f64b
commit e44c7fd3fd
5 changed files with 166 additions and 33 deletions

View File

@ -41,8 +41,13 @@ public struct Rect {
public class RefCountedObject {
protected int _refCount;
public @property int refCount() { return _refCount; }
public void addRef() { _refCount++; }
public void releaseRef() { if (--_refCount == 0) destroy(this); }
public void addRef() {
_refCount++;
}
public void releaseRef() {
if (--_refCount == 0)
destroy(this);
}
public ~this() {}
}
@ -56,23 +61,39 @@ public struct Ref(T) { // if (T is RefCountedObject)
if (_data !is null)
_data.addRef();
}
public void opAssign(Ref!T data) {
public this(this) {
if (_data !is null)
_data.addRef();
}
public ref Ref opAssign(ref Ref data) {
if (data._data == _data)
return;
return this;
if (_data !is null)
_data.releaseRef();
_data = data._data;
if (_data !is null)
_data.addRef();
return this;
}
public void opAssign(T data) {
public ref Ref opAssign(Ref data) {
if (data._data == _data)
return this;
if (_data !is null)
_data.releaseRef();
_data = data._data;
if (_data !is null)
_data.addRef();
return this;
}
public ref Ref opAssign(T data) {
if (data == _data)
return;
return this;
if (_data !is null)
_data.releaseRef();
_data = data;
if (_data !is null)
_data.addRef();
return this;
}
public void clear() {
if (_data !is null) {

View File

@ -47,6 +47,7 @@ class DrawBuf : RefCountedObject {
fillRect(Rect(left, top, right, bottom), color);
}
abstract public void fillRect(Rect rc, uint color);
abstract public void drawGlyph(int x, int y, ubyte[] src, int srcdx, int srcdy, uint color);
public void clear() {}
public ~this() { clear(); }
}
@ -59,6 +60,35 @@ class ColorDrawBufBase : DrawBuf {
public override void fillRect(int left, int top, int right, int bottom, uint color) {
fillRect(Rect(left, top, right, bottom), color);
}
public override void drawGlyph(int x, int y, ubyte[] src, int srcdx, int srcdy, uint color) {
bool clipping = !_clipRect.empty();
for (int yy = 0; yy < srcdy; yy++) {
int liney = y + yy;
if (clipping && (liney < _clipRect.top || liney >= _clipRect.bottom))
continue;
if (liney < 0 || liney >= _dy)
continue;
uint * row = scanLine(liney);
ubyte * srcrow = src.ptr + yy * srcdx;
for (int xx = 0; xx < srcdx; xx++) {
int colx = xx + x;
if (clipping && (colx < _clipRect.left || colx >= _clipRect.right))
continue;
if (colx < 0 || colx >= _dx)
continue;
uint alpha1 = srcrow[xx] ^ 255;
uint alpha2 = (color >> 24);
uint alpha = ((((alpha1 ^ 255) * (alpha2 ^ 255)) >> 8) ^ 255) & 255;
uint pixel = row[colx];
if (!alpha)
row[colx] = pixel;
else if (alpha < 255) {
// apply blending
row[colx] = blendARGB(pixel, color, alpha);
}
}
}
}
public override void fillRect(Rect rc, uint color) {
if (applyClipping(rc)) {
for (int y = rc.top; y < rc.bottom; y++) {

View File

@ -1,5 +1,8 @@
module dlangui.graphics.fonts;
import dlangui.core.types;
public import dlangui.graphics.drawbuf;
public import dlangui.core.types;
public import dlangui.core.logger;
import std.algorithm;
public enum FontFamily : int {
SansSerif,
@ -91,12 +94,53 @@ public class Font : RefCountedObject {
abstract public @property bool isNull();
// measure text string, return accumulated widths[] (distance to end of n-th character), returns number of measured chars.
abstract public int measureText(const dchar[] text, ref int[] widths, int maxWidth);
// draw text string to buffer
abstract public void drawText(DrawBuf buf, int x, int y, const dchar[] text, uint color);
abstract public Glyph * getCharGlyph(dchar ch);
public void clear() {}
public ~this() { clear(); }
}
alias FontRef = Ref!Font;
public struct FontList {
FontRef[] _list;
uint _len;
public ~this() {
for (uint i = 0; i < _len; i++) {
_list[i].clear();
}
}
// returns item by index
public ref FontRef get(int index) {
return _list[index];
}
// returns index of found item, -1 if not found
public int find(int size, int weight, bool italic, FontFamily family, string face) {
for (int i = 0; i < _list.length; i++) {
Font item = _list[i].get;
if (item.family != family)
continue;
if (item.size != size)
continue;
if (item.italic != italic || item.weight != weight)
continue;
if (!equal(item.face, face))
continue;
return i;
}
return -1;
}
public ref FontRef add(Font item) {
Log.d("FontList.add() enter");
if (_len >= _list.length) {
_list.length = _len < 16 ? 16 : _list.length * 2;
}
_list[_len++] = item;
Log.d("FontList.add() exit");
return _list[_len - 1];
}
}
public class FontManager {
static __gshared FontManager _instance;
public static @property void instance(FontManager manager) {
@ -105,6 +149,6 @@ public class FontManager {
public static @property FontManager instance() {
return _instance;
}
abstract public FontRef getFont(int size, int weight, bool italic, FontFamily family, string face);
abstract public ref FontRef getFont(int size, int weight, bool italic, FontFamily family, string face);
public ~this() {}
}

View File

@ -46,6 +46,10 @@ class Win32Font : Font {
public this() {
}
public ~this() {
Log.d("Deleting font");
clear();
}
public override void clear() {
if (_hfont !is null)
{
@ -174,6 +178,26 @@ class Win32Font : Font {
return _glyphCache.put(cast(ushort)glyphIndex, &g);
}
// draw text string to buffer
public override void drawText(DrawBuf buf, int x, int y, const dchar[] text, uint color) {
int[] widths;
int charsMeasured = measureText(text, widths, 3000);
for (int i = 0; i < charsMeasured; i++) {
int xx = (i > 0) ? widths[i - 1] : 0;
Glyph * glyph = getCharGlyph(text[i]);
if (glyph is null)
continue;
if ( glyph.blackBoxX && glyph.blackBoxY ) {
buf.drawGlyph( x + xx + glyph.originX,
y + _baseline - glyph.originY,
glyph.glyph,
glyph.blackBoxX,
glyph.blackBoxY,
color);
}
}
}
public override int measureText(const dchar[] text, ref int[] widths, int maxWidth) {
if (_hfont is null || _drawbuf is null || text.length == 0)
return 0;
@ -251,7 +275,7 @@ class Win32Font : Font {
class Win32FontManager : FontManager {
FontRef[] _activeFonts;
FontList _activeFonts;
FontDef[] _fontFaces;
FontDef*[string] _faceByName;
public this() {
@ -277,32 +301,23 @@ class Win32FontManager : FontManager {
Log.i("Found ", _fontFaces.length, " font faces");
return res!=0;
}
public override FontRef getFont(int size, int weight, bool italic, FontFamily family, string face) {
FontRef res;
FontRef _emptyFontRef;
public override ref FontRef getFont(int size, int weight, bool italic, FontFamily family, string face) {
Log.i("getFont()");
FontDef * def = findFace(family, face);
if (def !is null) {
for (int i = 0; i < _activeFonts.length; i++) {
Font item = _activeFonts[i].get;
if (item.family != def.family)
continue;
if (item.size != size)
continue;
if (item.italic != italic || item.weight != weight)
continue;
if (!equal(item.face, def.face))
continue;
res = _activeFonts[i];
break;
}
if (res.isNull) {
Win32Font item = new Win32Font();
if (!item.create(def, size, weight, italic))
return res;
res = item;
_activeFonts ~= res;
}
int index = _activeFonts.find(size, weight, italic, def.family, def.face);
if (index >= 0)
return _activeFonts.get(index);
Log.d("Creating new font");
Win32Font item = new Win32Font();
if (!item.create(def, size, weight, italic))
return _emptyFontRef;
Log.d("Adding to list of active fonts");
return _activeFonts.add(item);
} else {
return _emptyFontRef;
}
return res;
}
FontDef * findFace(FontFamily family) {
FontDef * res = null;

View File

@ -6,19 +6,42 @@ import dlangui.core.logger;
import dlangui.graphics.fonts;
import std.stdio;
class TestWidget : Widget {
public override void onDraw(DrawBuf buf) {
super.onDraw(buf);
FontRef font1;
FontRef font2;
Log.d("Testing opAssign");
font1 = font2;
Log.d("Testing copy constructor");
FontRef font3 = font2;
Log.d("On draw: getting font");
FontRef font = FontManager.instance.getFont(32, 400, false, FontFamily.SansSerif, "Arial");
Log.d("Got font, drawing text");
font.drawText(buf, _pos.left + 5, _pos.top + 5, "Text"d, 0x0000FF);
Log.d("Text is drawn successfully");
}
}
extern (C) int UIAppMain() {
Log.d("Some debug message");
Log.e("Sample error #", 22);
Window window = Platform.instance().createWindow("My Window", null);
Widget myWidget = new Widget();
Widget myWidget = new TestWidget();
window.mainWidget = myWidget;
window.show();
window.windowCaption = "New Window Caption";
Log.d("Before getFont");
FontRef font = FontManager.instance.getFont(32, 400, false, FontFamily.SansSerif, "Arial");
Log.d("After getFont");
assert(!font.isNull);
int[] widths;
dchar[] text = cast(dchar[])"Test string"d;
Log.d("Calling measureText");
int charsMeasured = font.measureText(text, widths, 1000);
assert(charsMeasured > 0);
int w = widths[charsMeasured - 1];