1 // Some of this code was originally written for the ScintillaGL project by:
2 // Copyright 2011 by Mykhailo Parfeniuk
3
4 #include <string.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <stddef.h>
8 #include <math.h>
9 #include <assert.h>
10
11 #include <vector>
12 #include <map>
13
14 #include "Platform.h"
15 #include "Scintilla.h"
16 #include "UniConversion.h"
17 #include "XPM.h"
18
19 #define STB_TRUETYPE_IMPLEMENTATION
20 #include "stb_truetype.h"
21 #include "Renderer.h"
22
23 #ifdef SCI_NAMESPACE
24 using namespace Scintilla;
25 #endif
26
27 //////////////////////////////////////////////////////////////////////////
28
29 // this is only used if we support loading external lexers, which we don't
Load(const char * modulePath)30 DynamicLibrary *DynamicLibrary::Load(const char *modulePath)
31 {
32 return NULL;
33 }
34
35 //////////////////////////////////////////////////////////////////////////
36
MakeRGBA(unsigned char r,unsigned char g,unsigned char b,unsigned char a=0xFF)37 ColourDesired MakeRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a=0xFF)
38 {
39 return a<<24 | b<<16 | g<<8 | r;
40 }
41
Chrome()42 ColourDesired Platform::Chrome()
43 {
44 return MakeRGBA(0xe0, 0xe0, 0xe0);
45 }
46
ChromeHighlight()47 ColourDesired Platform::ChromeHighlight()
48 {
49 return MakeRGBA(0xff, 0xff, 0xff);
50 }
51
DefaultFont()52 const char *Platform::DefaultFont()
53 {
54 return "Lucida Console";
55 }
56
DefaultFontSize()57 int Platform::DefaultFontSize()
58 {
59 return 10;
60 }
61
DoubleClickTime()62 unsigned int Platform::DoubleClickTime()
63 {
64 return 500; // Half a second
65 }
66
MouseButtonBounce()67 bool Platform::MouseButtonBounce()
68 {
69 return true;
70 }
71
Assert(const char * c,const char * file,int line)72 void Platform::Assert(const char *c, const char *file, int line)
73 {
74 char buffer[2000];
75 sprintf(buffer, "Assertion [%s] failed at %s %d", c, file, line);
76 strcat(buffer, "\r\n");
77 assert(false);
78 }
Minimum(int a,int b)79 int Platform::Minimum(int a, int b) { return a<b ? a : b; }
Maximum(int a,int b)80 int Platform::Maximum(int a, int b) { return a>b ? a : b; }
Clamp(int val,int minVal,int maxVal)81 int Platform::Clamp(int val, int minVal, int maxVal) { return Minimum( maxVal, Maximum( val, minVal ) ); }
82
83 #ifdef TRACE
DebugPrintf(const char * format,...)84 void Platform::DebugPrintf(const char *format, ...)
85 {
86 char buffer[2000];
87 va_list pArguments;
88 va_start(pArguments, format);
89 vsprintf(buffer,format,pArguments);
90 va_end(pArguments);
91 Platform::DebugDisplay(buffer);
92 }
93 #else
DebugPrintf(const char *,...)94 void Platform::DebugPrintf(const char *, ...)
95 {
96 }
97 #endif
98
99 //////////////////////////////////////////////////////////////////////////
100 // FONT
101
102 #define CHARACTER_COUNT 512 // first 512 chars of unicode should be sufficient
103
104 struct stbtt_Font
105 {
106 stbtt_fontinfo fontinfo;
107 stbtt_bakedchar cdata[CHARACTER_COUNT];
108 float scale;
109 Renderer::Texture * texture;
110 };
111
Font()112 Font::Font() : fid(0)
113 {
114 }
115
~Font()116 Font::~Font()
117 {
118 }
119
Create(const FontParameters & fp)120 void Font::Create(const FontParameters &fp)
121 {
122 stbtt_Font* newFont = new stbtt_Font;
123
124 FILE* f = fopen(fp.faceName, "rb");
125
126 assert(f);
127
128 fseek(f, 0, SEEK_END);
129 size_t len = ftell(f);
130 fseek(f, 0, SEEK_SET);
131
132 int texSize = 512;
133 unsigned char* buf = (unsigned char*)malloc(len);
134 fread(buf, 1, len, f);
135 fclose(f);
136
137 unsigned char* bmp = new unsigned char[texSize*texSize];
138
139 stbtt_BakeFontBitmap(buf, 0, fp.size, bmp, texSize, texSize, 0, CHARACTER_COUNT, newFont->cdata); // no guarantee this fits!
140
141 #ifdef _DEBUG
142 FILE* dump = fopen("font.raw", "wb");
143 fwrite(bmp,texSize,texSize,dump);
144 fclose(dump);
145 #endif // _DEBUG
146
147 newFont->texture = Renderer::CreateA8TextureFromData( texSize, texSize, bmp );
148
149 stbtt_InitFont(&newFont->fontinfo, buf, 0);
150
151 newFont->scale = stbtt_ScaleForPixelHeight(&newFont->fontinfo, fp.size);
152
153 delete [] bmp;
154
155 fid = newFont;
156 }
157
Release()158 void Font::Release()
159 {
160 if (fid)
161 {
162 free(((stbtt_Font*)fid)->fontinfo.data);
163 Renderer::ReleaseTexture( ((stbtt_Font*)fid)->texture );
164 delete (stbtt_Font*)fid;
165 }
166 }
167
168 //////////////////////////////////////////////////////////////////////////
169 // SURFACE
170
171 #ifdef SCI_NAMESPACE
172 namespace Scintilla {
173 #endif
174 class SurfaceImpl : public Surface {
175 ColourDesired penColour;
176 float currentX;
177 float currentY;
178 bool unicodeMode;
179 int codePage;
180 bool initialised;
181 PRectangle clipRect;
182 public:
183 SurfaceImpl();
184 virtual ~SurfaceImpl();
185
186 void Init(WindowID wid);
187 void Init(SurfaceID sid, WindowID wid);
188 void InitPixMap(int width, int height, Surface *surface, WindowID wid);
189
190 void Release();
191 bool Initialised();
192 void PenColour(ColourDesired fore);
193 int LogPixelsY();
194 int DeviceHeightFont(int points);
195 void MoveTo(float x, float y);
196 void LineTo(float x, float y);
197 void Polygon(Point *pts, int npts, ColourDesired fore, ColourDesired back);
198 void RectangleDraw(PRectangle rc, ColourDesired fore, ColourDesired back);
199 void FillRectangle(PRectangle rc, ColourDesired back);
200 void FillRectangle(PRectangle rc, Surface &surfacePattern);
201 void RoundedRectangle(PRectangle rc, ColourDesired fore, ColourDesired back);
202 void AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill, int alphaFill,
203 ColourDesired outline, int alphaOutline, int flags);
204 void Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back);
205 void Copy(PRectangle rc, Point from, Surface &surfaceSource);
206
207 //virtual void DrawPixmap(PRectangle rc, Point from, Pixmap pixmap);
208 virtual void DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage);
209
210 void DrawTextBase(PRectangle rc, Font &font, float ybase, const char *s, int len, ColourDesired fore);
211 void DrawTextNoClip(PRectangle rc, Font &font, float ybase, const char *s, int len, ColourDesired fore, ColourDesired back);
212 void DrawTextClipped(PRectangle rc, Font &font, float ybase, const char *s, int len, ColourDesired fore, ColourDesired back);
213 void DrawTextTransparent(PRectangle rc, Font &font, float ybase, const char *s, int len, ColourDesired fore);
214 void MeasureWidths(Font &font, const char *s, int len, float *positions);
215 float WidthText(Font &font, const char *s, int len);
216 float WidthChar(Font &font, char ch);
217 float Ascent(Font &font);
218 float Descent(Font &font);
219 float InternalLeading(Font &font);
220 float ExternalLeading(Font &font);
221 float Height(Font &font);
222 float AverageCharWidth(Font &font);
223
224 void MoveTo(int x, int y);
225 void LineTo(int x, int y);
226
227 void SetClip(PRectangle rc);
228 void FlushCachedState();
229
230 void SetUnicodeMode(bool unicodeMode_);
231 void SetDBCSMode(int codePage);
232 };
233
234 #ifdef SCI_NAMESPACE
235 }
236 #endif
237
SurfaceImpl()238 SurfaceImpl::SurfaceImpl()
239 : currentX(0), currentY(0)
240 {
241 unicodeMode = false;
242 codePage = 0;
243 initialised = false;
244 }
245
~SurfaceImpl()246 SurfaceImpl::~SurfaceImpl()
247 {
248 }
249
Init(WindowID wid)250 void SurfaceImpl::Init( WindowID wid )
251 {
252 initialised = true;
253 }
254
Init(SurfaceID sid,WindowID wid)255 void SurfaceImpl::Init( SurfaceID sid, WindowID wid )
256 {
257 initialised = true;
258 }
259
InitPixMap(int width,int height,Surface * surface,WindowID wid)260 void SurfaceImpl::InitPixMap( int width, int height, Surface *surface, WindowID wid )
261 {
262 initialised = true;
263 }
264
Release()265 void SurfaceImpl::Release()
266 {
267 }
268
Initialised()269 bool SurfaceImpl::Initialised()
270 {
271 return initialised;
272 }
273
PenColour(ColourDesired fore)274 void SurfaceImpl::PenColour(ColourDesired fore)
275 {
276 penColour = fore;
277 }
278
LogPixelsY()279 int SurfaceImpl::LogPixelsY()
280 {
281 return 72;
282 }
283
DeviceHeightFont(int points)284 int SurfaceImpl::DeviceHeightFont(int points)
285 {
286 int logPix = LogPixelsY();
287 return (points * logPix + logPix / 2) / 72;
288 }
289
MoveTo(float x,float y)290 void SurfaceImpl::MoveTo(float x, float y)
291 {
292 currentX = x;
293 currentY = y;
294 }
295
LineTo(float targetX,float targetY)296 void SurfaceImpl::LineTo(float targetX, float targetY)
297 {
298 Renderer::RenderLine(
299 Renderer::Vertex( currentX+0.5f, currentY+0.5f, (unsigned int)penColour.AsLong() ),
300 Renderer::Vertex( targetX+0.5f, targetY+0.5f, (unsigned int)penColour.AsLong() )
301 );
302 currentX = targetX;
303 currentY = targetY;
304 }
305
MoveTo(int x,int y)306 void SurfaceImpl::MoveTo( int x, int y )
307 {
308 MoveTo( (float)x, (float)y );
309 }
310
LineTo(int x,int y)311 void SurfaceImpl::LineTo( int x, int y )
312 {
313 LineTo( (float)x, (float)y );
314 }
315
Polygon(Point *,int,ColourDesired,ColourDesired)316 void SurfaceImpl::Polygon(Point* /*pts*/, int /*npts*/, ColourDesired /*fore*/, ColourDesired /*back*/)
317 {
318 assert(!"Implemented");
319 }
320
RectangleDraw(PRectangle rc,ColourDesired fore,ColourDesired back)321 void SurfaceImpl::RectangleDraw(PRectangle rc, ColourDesired fore, ColourDesired back)
322 {
323 FillRectangle(rc, back);
324 PenColour(fore);
325 MoveTo( rc.left , rc.top );
326 LineTo( rc.right, rc.top );
327 LineTo( rc.right, rc.bottom );
328 LineTo( rc.left, rc.bottom);
329 LineTo( rc.left, rc.top );
330 }
331
FillRectangle(PRectangle rc,ColourDesired back)332 void SurfaceImpl::FillRectangle(PRectangle rc, ColourDesired back)
333 {
334 Renderer::BindTexture(NULL);
335
336 Renderer::RenderQuad(
337 Renderer::Vertex( rc.left , rc.top, (unsigned int)back.AsLong() ),
338 Renderer::Vertex( rc.right, rc.top, (unsigned int)back.AsLong() ),
339 Renderer::Vertex( rc.right, rc.bottom, (unsigned int)back.AsLong() ),
340 Renderer::Vertex( rc.left , rc.bottom, (unsigned int)back.AsLong() )
341 );
342 }
343
FillRectangle(PRectangle rc,Surface & surfacePattern)344 void SurfaceImpl::FillRectangle(PRectangle rc, Surface & surfacePattern)
345 {
346 FillRectangle( rc, 0xd0000000 );
347 }
348
RoundedRectangle(PRectangle rc,ColourDesired fore,ColourDesired back)349 void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourDesired fore, ColourDesired back)
350 {
351 RectangleDraw( rc, fore, back );
352 }
353
AlphaRectangle(PRectangle rc,int,ColourDesired fill,int alphaFill,ColourDesired,int,int)354 void SurfaceImpl::AlphaRectangle(PRectangle rc, int /*cornerSize*/, ColourDesired fill, int alphaFill,
355 ColourDesired /*outline*/, int /*alphaOutline*/, int /*flags*/)
356 {
357 unsigned int back = (fill.AsLong() & 0xFFFFFF) | ((alphaFill & 0xFF) << 24);
358 FillRectangle(rc, back);
359 }
360
DrawRGBAImage(PRectangle rc,int width,int height,const unsigned char * pixelsImage)361 void SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage)
362 {
363 assert(!"Implemented");
364 }
365
Ellipse(PRectangle,ColourDesired,ColourDesired)366 void SurfaceImpl::Ellipse(PRectangle /*rc*/, ColourDesired /*fore*/, ColourDesired /*back*/)
367 {
368 assert(!"Implemented");
369 }
370
Copy(PRectangle rc,Point from,Surface & surfaceSource)371 void SurfaceImpl::Copy( PRectangle rc, Point from, Surface &surfaceSource )
372 {
373 // we don't assert here because this is often used
374 // however, we don't support it right now
375 }
376
DrawTextBase(PRectangle rc,Font & font,float ybase,const char * str,int len,ColourDesired fore)377 void SurfaceImpl::DrawTextBase(PRectangle rc, Font &font, float ybase, const char *str, int len, ColourDesired fore)
378 {
379 stbtt_Font* realFont = (stbtt_Font*)font.GetID();
380
381 Renderer::BindTexture( realFont->texture );
382 float x = rc.left, y = ybase;
383 while (len-- > 0)
384 {
385 unsigned int c = *str;
386 unsigned int charLength = UTF8CharLength(c);
387 if (charLength > 1)
388 {
389 c = 0;
390 UTF16FromUTF8( str, charLength, (wchar_t*)&c, sizeof(unsigned int) );
391 }
392 if (c >= CHARACTER_COUNT)
393 c = '?';
394 stbtt_aligned_quad quad;
395 stbtt_GetBakedQuad( realFont->cdata, realFont->texture->width, realFont->texture->height, c, &x, &y, &quad, 1 );
396
397 Renderer::RenderQuad(
398 Renderer::Vertex( quad.x0, quad.y0, (unsigned int)fore.AsLong(), quad.s0, quad.t0 ),
399 Renderer::Vertex( quad.x1, quad.y0, (unsigned int)fore.AsLong(), quad.s1, quad.t0 ),
400 Renderer::Vertex( quad.x1, quad.y1, (unsigned int)fore.AsLong(), quad.s1, quad.t1 ),
401 Renderer::Vertex( quad.x0, quad.y1, (unsigned int)fore.AsLong(), quad.s0, quad.t1 )
402 );
403 str += charLength;
404 len -= charLength - 1;
405 }
406 }
407
DrawTextNoClip(PRectangle rc,Font & font,float ybase,const char * s,int len,ColourDesired fore,ColourDesired)408 void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font, float ybase, const char *s, int len,
409 ColourDesired fore, ColourDesired /*back*/)
410 {
411 DrawTextBase(rc, font, ybase, s, len, fore);
412 }
413
DrawTextClipped(PRectangle rc,Font & font,float ybase,const char * s,int len,ColourDesired fore,ColourDesired)414 void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font, float ybase, const char *s, int len,
415 ColourDesired fore, ColourDesired /*back*/)
416 {
417 DrawTextBase(rc, font, ybase, s, len, fore);
418 }
419
DrawTextTransparent(PRectangle rc,Font & font,float ybase,const char * s,int len,ColourDesired fore)420 void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font, float ybase, const char *s, int len,
421 ColourDesired fore)
422 {
423 DrawTextBase(rc, font, ybase, s, len, fore);
424 }
425
MeasureWidths(Font & font,const char * str,int len,float * positions)426 void SurfaceImpl::MeasureWidths(Font & font, const char *str, int len, float *positions)
427 {
428 stbtt_Font* realFont = (stbtt_Font*)font.GetID();
429
430 float position = 0;
431 const char * p = str;
432 while (len-- > 0)
433 {
434 unsigned int c = *p;
435 unsigned int charLength = UTF8CharLength(c);
436 if (charLength > 1)
437 {
438 c = 0;
439 UTF16FromUTF8( str, charLength, (wchar_t*)&c, sizeof(unsigned int) );
440 }
441 if (c >= CHARACTER_COUNT)
442 c = '?';
443
444 int advance = 0, leftBearing = 0;
445
446 stbtt_GetCodepointHMetrics(&realFont->fontinfo, c, &advance, &leftBearing);
447
448 position += advance;
449 for (unsigned int i=0; i<charLength; i++) // we need to loop here because UTF8 characters count as multiple unless their position is the same
450 *positions++ = position*realFont->scale;
451
452 p += charLength;
453 len -= charLength - 1;
454 }
455 }
456
WidthText(Font & font,const char * str,int len)457 float SurfaceImpl::WidthText(Font & font, const char *str, int len)
458 {
459 stbtt_Font* realFont = (stbtt_Font*)font.GetID();
460
461 float position = 0;
462 while (len-- > 0)
463 {
464 unsigned int c = *str;
465 unsigned int charLength = UTF8CharLength(c);
466 if (charLength > 1)
467 {
468 c = 0;
469 UTF16FromUTF8( str, charLength, (wchar_t*)&c, sizeof(unsigned int) );
470 }
471 if (c >= CHARACTER_COUNT)
472 c = '?';
473
474 int advance = 0, leftBearing = 0;
475 stbtt_GetCodepointHMetrics(&realFont->fontinfo, c, &advance, &leftBearing);
476 position += advance*realFont->scale;//TODO: +Kerning
477
478 str += charLength;
479 len -= charLength - 1;
480 }
481 return position;
482 }
483
WidthChar(Font & font,char ch)484 float SurfaceImpl::WidthChar(Font &font, char ch)
485 {
486 stbtt_Font* realFont = (stbtt_Font*)font.GetID();
487 int advance, leftBearing;
488 stbtt_GetCodepointHMetrics(&realFont->fontinfo, ch, &advance, &leftBearing);
489 return advance * realFont->scale;
490 }
491
Ascent(Font & font)492 float SurfaceImpl::Ascent(Font &font)
493 {
494 stbtt_Font* realFont = (stbtt_Font*)font.GetID();
495 int ascent, descent, lineGap;
496 stbtt_GetFontVMetrics(&realFont->fontinfo, &ascent, &descent, &lineGap);
497 return ascent * realFont->scale;
498 }
499
Descent(Font & font)500 float SurfaceImpl::Descent(Font &font)
501 {
502 stbtt_Font* realFont = (stbtt_Font*)font.GetID();
503 int ascent, descent, lineGap;
504 stbtt_GetFontVMetrics(&realFont->fontinfo, &ascent, &descent, &lineGap);
505 return -descent * realFont->scale;
506 }
507
InternalLeading(Font &)508 float SurfaceImpl::InternalLeading(Font &)
509 {
510 //WTF is this?????
511 return 0;
512 }
513
ExternalLeading(Font & font)514 float SurfaceImpl::ExternalLeading(Font& font)
515 {
516 //WTF is this?????
517 stbtt_Font* realFont = (stbtt_Font*)font.GetID();
518 int ascent, descent, lineGap;
519 stbtt_GetFontVMetrics(&realFont->fontinfo, &ascent, &descent, &lineGap);
520 return lineGap * realFont->scale;
521 }
522
Height(Font & font)523 float SurfaceImpl::Height(Font &font)
524 {
525 return Ascent(font) + Descent(font);
526 }
527
AverageCharWidth(Font & font)528 float SurfaceImpl::AverageCharWidth(Font &font)
529 {
530 return WidthChar(font, 'n');
531 }
532
SetClip(PRectangle rc)533 void SurfaceImpl::SetClip(PRectangle rc)
534 {
535 // we deal with this in the renderer
536 }
537
FlushCachedState()538 void SurfaceImpl::FlushCachedState()
539 {}
540
SetUnicodeMode(bool mode)541 void SurfaceImpl::SetUnicodeMode( bool mode )
542 {
543 unicodeMode = mode;
544 }
545
SetDBCSMode(int cp)546 void SurfaceImpl::SetDBCSMode( int cp )
547 {
548 codePage = cp;
549 }
550
Allocate(int technology)551 Surface *Surface::Allocate(int technology)
552 {
553 return new SurfaceImpl;
554 }
555
556 //////////////////////////////////////////////////////////////////////////
557 // Window
558
~Window()559 Window::~Window()
560 {
561 }
562
Destroy()563 void Window::Destroy()
564 {
565 }
566
HasFocus()567 bool Window::HasFocus()
568 {
569 return false;
570 }
571
572 std::map<Scintilla::WindowID,Scintilla::PRectangle> rects;
GetPosition()573 PRectangle Window::GetPosition()
574 {
575 return rects[wid];
576 }
577
SetPosition(PRectangle rc)578 void Window::SetPosition(PRectangle rc)
579 {
580 rects[wid] = rc;
581 }
582
SetPositionRelative(PRectangle rc,Window w)583 void Window::SetPositionRelative(PRectangle rc, Window w)
584 {
585 }
586
GetClientPosition()587 PRectangle Window::GetClientPosition()
588 {
589 return PRectangle( 0, 0, rects[wid].Width(), rects[wid].Height() );
590 }
591
Show(bool show)592 void Window::Show(bool show)
593 {
594 }
595
InvalidateAll()596 void Window::InvalidateAll()
597 {
598 }
599
InvalidateRectangle(PRectangle rc)600 void Window::InvalidateRectangle(PRectangle rc)
601 {
602 }
603
SetFont(Font & font)604 void Window::SetFont(Font &font)
605 {
606 }
607
SetCursor(Cursor curs)608 void Window::SetCursor(Cursor curs)
609 {
610 }
611
GetMonitorRect(Point pt)612 PRectangle Window::GetMonitorRect(Point pt)
613 {
614 return PRectangle( 0, 0, Renderer::nWidth, Renderer::nHeight );
615 }
616
617 //////////////////////////////////////////////////////////////////////////
618 // Menus
619
Menu()620 Menu::Menu() : mid(0)
621 {
622 assert(!"Implemented");
623 }
624
CreatePopUp()625 void Menu::CreatePopUp()
626 {
627 assert(!"Implemented");
628 }
629
Destroy()630 void Menu::Destroy()
631 {
632 assert(!"Implemented");
633 }
634
Show(Point pt,Window & w)635 void Menu::Show(Point pt, Window &w)
636 {
637 assert(!"Implemented");
638 }
639
640 //////////////////////////////////////////////////////////////////////////
641 // ListBox implementation
642
Allocate()643 ListBox *ListBox::Allocate()
644 {
645 return NULL;
646 }
647