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