diff options
-rw-r--r-- | cocoa/PlatCocoa.h | 24 | ||||
-rw-r--r-- | cocoa/PlatCocoa.mm | 53 | ||||
-rw-r--r-- | cocoa/QuartzTextStyleAttribute.h | 3 | ||||
-rw-r--r-- | cocoa/ScintillaCocoa.mm | 4 | ||||
-rw-r--r-- | cocoa/ScintillaFramework/ScintillaFramework.xcodeproj/project.pbxproj | 4 | ||||
-rw-r--r-- | cocoa/ScintillaTest/AppController.mm | 2 | ||||
-rw-r--r-- | doc/ScintillaDoc.html | 34 | ||||
-rw-r--r-- | gtk/PlatGTK.cxx | 163 | ||||
-rw-r--r-- | gtk/ScintillaGTK.cxx | 8 | ||||
-rw-r--r-- | include/Platform.h | 88 | ||||
-rw-r--r-- | include/Scintilla.h | 12 | ||||
-rw-r--r-- | include/Scintilla.iface | 28 | ||||
-rw-r--r-- | src/AutoComplete.cxx | 4 | ||||
-rw-r--r-- | src/AutoComplete.h | 2 | ||||
-rw-r--r-- | src/CallTip.cxx | 8 | ||||
-rw-r--r-- | src/CallTip.h | 2 | ||||
-rw-r--r-- | src/Editor.cxx | 106 | ||||
-rw-r--r-- | src/Editor.h | 8 | ||||
-rw-r--r-- | src/FontQuality.h | 3 | ||||
-rw-r--r-- | src/PositionCache.cxx | 14 | ||||
-rw-r--r-- | src/PositionCache.h | 10 | ||||
-rw-r--r-- | src/ScintillaBase.cxx | 3 | ||||
-rw-r--r-- | src/Style.cxx | 20 | ||||
-rw-r--r-- | src/Style.h | 8 | ||||
-rw-r--r-- | src/ViewStyle.cxx | 22 | ||||
-rw-r--r-- | src/ViewStyle.h | 3 | ||||
-rw-r--r-- | win32/PlatWin.cxx | 1214 | ||||
-rw-r--r-- | win32/PlatWin.h | 13 | ||||
-rw-r--r-- | win32/ScintillaWin.cxx | 180 |
29 files changed, 1594 insertions, 449 deletions
diff --git a/cocoa/PlatCocoa.h b/cocoa/PlatCocoa.h index 0e3c5f2e2..7f6a59705 100644 --- a/cocoa/PlatCocoa.h +++ b/cocoa/PlatCocoa.h @@ -96,20 +96,20 @@ public: void DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage); void Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back); void Copy(PRectangle rc, Scintilla::Point from, Surface &surfaceSource); - void DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, + void DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back); - void DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, + void DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back); - void DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore); - void MeasureWidths(Font &font_, const char *s, int len, int *positions); - int WidthText(Font &font_, const char *s, int len); - int WidthChar(Font &font_, char ch); - int Ascent(Font &font_); - int Descent(Font &font_); - int InternalLeading(Font &font_); - int ExternalLeading(Font &font_); - int Height(Font &font_); - int AverageCharWidth(Font &font_); + void DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore); + void MeasureWidths(Font &font_, const char *s, int len, XYPOSITION *positions); + XYPOSITION WidthText(Font &font_, const char *s, int len); + XYPOSITION WidthChar(Font &font_, char ch); + XYPOSITION Ascent(Font &font_); + XYPOSITION Descent(Font &font_); + XYPOSITION InternalLeading(Font &font_); + XYPOSITION ExternalLeading(Font &font_); + XYPOSITION Height(Font &font_); + XYPOSITION AverageCharWidth(Font &font_); int SetPalette(Scintilla::Palette *pal, bool inBackGround); void SetClip(PRectangle rc); diff --git a/cocoa/PlatCocoa.mm b/cocoa/PlatCocoa.mm index fd66f671f..ce112f853 100644 --- a/cocoa/PlatCocoa.mm +++ b/cocoa/PlatCocoa.mm @@ -156,8 +156,7 @@ static int FontCharacterSet(Font &f) { /** * Creates a CTFontRef with the given properties. */ -void Font::Create(const char *faceName, int characterSet, int size, bool bold, bool italic, - int /* extraFontFlag */) +void Font::Create(const FontParameters &fp) { Release(); @@ -165,9 +164,9 @@ void Font::Create(const char *faceName, int characterSet, int size, bool bold, b fid = style; // Create the font with attributes - QuartzFont font(faceName, strlen(faceName), size, bold, italic); + QuartzFont font(fp.faceName, strlen(fp.faceName), fp.size, fp.weight, fp.italic); CTFontRef fontRef = font.getFontID(); - style->setFontRef(fontRef, characterSet); + style->setFontRef(fontRef, fp.characterSet); } //-------------------------------------------------------------------------------------------------- @@ -507,6 +506,9 @@ void SurfaceImpl::FillRectangle(PRectangle rc, ColourAllocated back) if (gc) { FillColour(back); + // Snap rectangle boundaries to nearest int + rc.left = lround(rc.left); + rc.right = lround(rc.right); CGRect rect = PRectangleToCGRect(rc); CGContextFillRect(gc, rect); } @@ -641,7 +643,10 @@ void Scintilla::SurfaceImpl::AlphaRectangle(PRectangle rc, int /*cornerSize*/, C { if ( gc ) { ColourDesired colour( fill.AsLong() ); - + + // Snap rectangle boundaries to nearest int + rc.left = lround(rc.left); + rc.right = lround(rc.right); // Set the Fill color to match CGContextSetRGBFillColor( gc, colour.GetRed() / 255.0, colour.GetGreen() / 255.0, colour.GetBlue() / 255.0, alphaFill / 255.0 ); CGRect rect = PRectangleToCGRect( rc ); @@ -836,7 +841,7 @@ void SurfaceImpl::Copy(PRectangle rc, Scintilla::Point from, Surface &surfaceSou //-------------------------------------------------------------------------------------------------- -void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len, +void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back) { FillRectangle(rc, back); @@ -845,7 +850,7 @@ void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const ch //-------------------------------------------------------------------------------------------------- -void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, +void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back) { CGContextSaveGState(gc); @@ -913,7 +918,7 @@ CFStringEncoding EncodingFromCharacterSet(bool unicode, int characterSet) } } -void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, +void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore) { CFStringEncoding encoding = EncodingFromCharacterSet(unicodeMode, FontCharacterSet(font_)); @@ -943,7 +948,7 @@ static size_t utf8LengthFromLead(unsigned char uch) { //-------------------------------------------------------------------------------------------------- -void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positions) +void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, XYPOSITION *positions) { CFStringEncoding encoding = EncodingFromCharacterSet(unicodeMode, FontCharacterSet(font_)); textLayout->setText (reinterpret_cast<const UInt8*>(s), len, encoding, *reinterpret_cast<QuartzTextStyle*>(font_.GetID())); @@ -962,7 +967,7 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positi size_t codeUnits = (lenChar < 4) ? 1 : 2; CGFloat xPosition = CTLineGetOffsetForStringIndex(mLine, ui+1, NULL); for (unsigned int bytePos=0; (bytePos<lenChar) && (i<len); bytePos++) { - positions[i++] = static_cast<int>(lround(xPosition)); + positions[i++] = xPosition; } ui += codeUnits; } @@ -978,20 +983,20 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positi size_t lenChar = Platform::IsDBCSLeadByte(codePage, s[i]) ? 2 : 1; CGFloat xPosition = CTLineGetOffsetForStringIndex(mLine, ui+1, NULL); for (unsigned int bytePos=0; (bytePos<lenChar) && (i<len); bytePos++) { - positions[i++] = static_cast<int>(lround(xPosition)); + positions[i++] = xPosition; } ui++; } } else { // Single byte encoding for (int i=0;i<len;i++) { CGFloat xPosition = CTLineGetOffsetForStringIndex(mLine, i+1, NULL); - positions[i] = static_cast<int>(lround(xPosition)); + positions[i] = xPosition; } } } -int SurfaceImpl::WidthText(Font &font_, const char *s, int len) { +XYPOSITION SurfaceImpl::WidthText(Font &font_, const char *s, int len) { if (font_.GetID()) { CFStringEncoding encoding = EncodingFromCharacterSet(unicodeMode, FontCharacterSet(font_)); @@ -1002,7 +1007,7 @@ int SurfaceImpl::WidthText(Font &font_, const char *s, int len) { return 1; } -int SurfaceImpl::WidthChar(Font &font_, char ch) { +XYPOSITION SurfaceImpl::WidthChar(Font &font_, char ch) { char str[2] = { ch, '\0' }; if (font_.GetID()) { @@ -1019,7 +1024,7 @@ int SurfaceImpl::WidthChar(Font &font_, char ch) { const char sizeString[] = "`~!@#$%^&*()-_=+\\|[]{};:\"\'<,>.?/1234567890" "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; -int SurfaceImpl::Ascent(Font &font_) { +XYPOSITION SurfaceImpl::Ascent(Font &font_) { if (!font_.GetID()) return 1; @@ -1028,7 +1033,7 @@ int SurfaceImpl::Ascent(Font &font_) { } -int SurfaceImpl::Descent(Font &font_) { +XYPOSITION SurfaceImpl::Descent(Font &font_) { if (!font_.GetID()) return 1; @@ -1037,11 +1042,11 @@ int SurfaceImpl::Descent(Font &font_) { } -int SurfaceImpl::InternalLeading(Font &) { +XYPOSITION SurfaceImpl::InternalLeading(Font &) { return 0; } -int SurfaceImpl::ExternalLeading(Font &font_) { +XYPOSITION SurfaceImpl::ExternalLeading(Font &font_) { if (!font_.GetID()) return 1; @@ -1050,13 +1055,13 @@ int SurfaceImpl::ExternalLeading(Font &font_) { } -int SurfaceImpl::Height(Font &font_) { +XYPOSITION SurfaceImpl::Height(Font &font_) { int ht = Ascent(font_) + Descent(font_); return ht; } -int SurfaceImpl::AverageCharWidth(Font &font_) { +XYPOSITION SurfaceImpl::AverageCharWidth(Font &font_) { if (!font_.GetID()) return 1; @@ -1089,7 +1094,7 @@ void SurfaceImpl::SetDBCSMode(int codePage_) { codePage = codePage_; } -Surface *Surface::Allocate() +Surface *Surface::Allocate(int) { return new SurfaceImpl(); } @@ -1368,7 +1373,7 @@ static NSImage* ImageFromXPM(XPM* pxpm) const int width = pxpm->GetWidth(); const int height = pxpm->GetHeight(); PRectangle rcxpm(0, 0, width, height); - Surface* surfaceXPM = Surface::Allocate(); + Surface* surfaceXPM = Surface::Allocate(SC_TECHNOLOGY_DEFAULT); if (surfaceXPM) { surfaceXPM->InitPixMap(width, height, NULL, NULL); @@ -1510,7 +1515,7 @@ public: // ListBox methods void SetFont(Font& font); - void Create(Window& parent, int ctrlID, Scintilla::Point pt, int lineHeight_, bool unicodeMode_); + void Create(Window& parent, int ctrlID, Scintilla::Point pt, int lineHeight_, bool unicodeMode_, int technology_); void SetAverageCharWidth(int width); void SetVisibleRows(int rows); int GetVisibleRows() const; @@ -1595,7 +1600,7 @@ ListBox* ListBox::Allocate() } void ListBoxImpl::Create(Window& /*parent*/, int /*ctrlID*/, Scintilla::Point pt, - int lineHeight_, bool unicodeMode_) + int lineHeight_, bool unicodeMode_, int) { lineHeight = lineHeight_; unicodeMode = unicodeMode_; diff --git a/cocoa/QuartzTextStyleAttribute.h b/cocoa/QuartzTextStyleAttribute.h index 33c49281c..b9698645e 100644 --- a/cocoa/QuartzTextStyleAttribute.h +++ b/cocoa/QuartzTextStyleAttribute.h @@ -16,12 +16,13 @@ class QuartzFont { public: /** Create a font style from a name. */ - QuartzFont( const char* name, size_t length, float size, bool bold, bool italic ) + QuartzFont( const char* name, size_t length, float size, int weight, bool italic ) { assert( name != NULL && length > 0 && name[length] == '\0' ); CFStringRef fontName = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingMacRoman); assert(fontName != NULL); + bool bold = weight > SC_WEIGHT_NORMAL; if (bold || italic) { diff --git a/cocoa/ScintillaCocoa.mm b/cocoa/ScintillaCocoa.mm index 089568d66..7927652a7 100644 --- a/cocoa/ScintillaCocoa.mm +++ b/cocoa/ScintillaCocoa.mm @@ -702,7 +702,7 @@ void ScintillaCocoa::Paste(bool forceRectangular) void ScintillaCocoa::CTPaint(void* gc, NSRect rc) { #pragma unused(rc) - Surface *surfaceWindow = Surface::Allocate(); + Surface *surfaceWindow = Surface::Allocate(SC_TECHNOLOGY_DEFAULT); if (surfaceWindow) { surfaceWindow->Init(gc, wMain.GetID()); surfaceWindow->SetUnicodeMode(SC_CP_UTF8 == ct.codePage); @@ -1251,7 +1251,7 @@ void ScintillaCocoa::SyncPaint(void* gc, PRectangle rc) rcPaint = rc; PRectangle rcText = GetTextRectangle(); paintingAllText = rcPaint.Contains(rcText); - Surface *sw = Surface::Allocate(); + Surface *sw = Surface::Allocate(SC_TECHNOLOGY_DEFAULT); if (sw) { sw->Init(gc, wMain.GetID()); diff --git a/cocoa/ScintillaFramework/ScintillaFramework.xcodeproj/project.pbxproj b/cocoa/ScintillaFramework/ScintillaFramework.xcodeproj/project.pbxproj index 7765983a8..5ec9eb93a 100644 --- a/cocoa/ScintillaFramework/ScintillaFramework.xcodeproj/project.pbxproj +++ b/cocoa/ScintillaFramework/ScintillaFramework.xcodeproj/project.pbxproj @@ -955,7 +955,7 @@ SCI_LEXER, ); GCC_VERSION = com.apple.compilers.llvmgcc42; - GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNINITIALIZED_AUTOS = NO; GCC_WARN_UNKNOWN_PRAGMAS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_LABEL = YES; @@ -984,7 +984,7 @@ SCI_LEXER, ); GCC_VERSION = com.apple.compilers.llvmgcc42; - GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNINITIALIZED_AUTOS = NO; GCC_WARN_UNKNOWN_PRAGMAS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_LABEL = YES; diff --git a/cocoa/ScintillaTest/AppController.mm b/cocoa/ScintillaTest/AppController.mm index 24941ffe2..294704f02 100644 --- a/cocoa/ScintillaTest/AppController.mm +++ b/cocoa/ScintillaTest/AppController.mm @@ -116,7 +116,7 @@ const char user_keywords[] = // Definition of own keywords, not used by MySQL. [mEditor setReferenceProperty: SCI_SETKEYWORDS parameter: 7 value: user_keywords]; // Colors and styles for various syntactic elements. First the default style. - [mEditor setStringProperty: SCI_STYLESETFONT parameter: STYLE_DEFAULT value: @"Andale Mono"]; + [mEditor setStringProperty: SCI_STYLESETFONT parameter: STYLE_DEFAULT value: @"Helvetica"]; // [mEditor setStringProperty: SCI_STYLESETFONT parameter: STYLE_DEFAULT value: @"Monospac821 BT"]; // Very pleasing programmer's font. [mEditor setGeneralProperty: SCI_STYLESETSIZE parameter: STYLE_DEFAULT value: 14]; [mEditor setColorProperty: SCI_STYLESETFORE parameter: STYLE_DEFAULT value: [NSColor blackColor]]; diff --git a/doc/ScintillaDoc.html b/doc/ScintillaDoc.html index c733db471..c0b0c7a6f 100644 --- a/doc/ScintillaDoc.html +++ b/doc/ScintillaDoc.html @@ -2392,9 +2392,15 @@ struct Sci_TextToFind { <a class="message" href="#SCI_STYLESETSIZE">SCI_STYLESETSIZE(int styleNumber, int sizeInPoints)</a><br /> <a class="message" href="#SCI_STYLEGETSIZE">SCI_STYLEGETSIZE(int styleNumber)</a><br /> + <a class="message" href="#SCI_STYLESETSIZEFRACTIONAL">SCI_STYLESETSIZEFRACTIONAL(int styleNumber, int + sizeInHundredthPoints)</a><br /> + <a class="message" href="#SCI_STYLEGETSIZEFRACTIONAL">SCI_STYLEGETSIZEFRACTIONAL(int styleNumber)</a><br /> <a class="message" href="#SCI_STYLESETBOLD">SCI_STYLESETBOLD(int styleNumber, bool bold)</a><br /> <a class="message" href="#SCI_STYLEGETBOLD">SCI_STYLEGETBOLD(int styleNumber)</a><br /> + <a class="message" href="#SCI_STYLESETWEIGHT">SCI_STYLESETWEIGHT(int styleNumber, int + weight)</a><br /> + <a class="message" href="#SCI_STYLEGETWEIGHT">SCI_STYLEGETWEIGHT(int styleNumber)</a><br /> <a class="message" href="#SCI_STYLESETITALIC">SCI_STYLESETITALIC(int styleNumber, bool italic)</a><br /> <a class="message" href="#SCI_STYLEGETITALIC">SCI_STYLEGETITALIC(int styleNumber)</a><br /> @@ -2443,8 +2449,12 @@ struct Sci_TextToFind { <b id="SCI_STYLEGETFONT">SCI_STYLEGETFONT(int styleNumber, char *fontName)</b><br /> <b id="SCI_STYLESETSIZE">SCI_STYLESETSIZE(int styleNumber, int sizeInPoints)</b><br /> <b id="SCI_STYLEGETSIZE">SCI_STYLEGETSIZE(int styleNumber)</b><br /> + <b id="SCI_STYLESETSIZEFRACTIONAL">SCI_STYLESETSIZEFRACTIONAL(int styleNumber, int sizeInHundredthPoints)</b><br /> + <b id="SCI_STYLEGETSIZEFRACTIONAL">SCI_STYLEGETSIZEFRACTIONAL(int styleNumber)</b><br /> <b id="SCI_STYLESETBOLD">SCI_STYLESETBOLD(int styleNumber, bool bold)</b><br /> <b id="SCI_STYLEGETBOLD">SCI_STYLEGETBOLD(int styleNumber)</b><br /> + <b id="SCI_STYLESETWEIGHT">SCI_STYLESETWEIGHT(int styleNumber, int weight)</b><br /> + <b id="SCI_STYLEGETWEIGHT">SCI_STYLEGETWEIGHT(int styleNumber)</b><br /> <b id="SCI_STYLESETITALIC">SCI_STYLESETITALIC(int styleNumber, bool italic)</b><br /> <b id="SCI_STYLEGETITALIC">SCI_STYLEGETITALIC(int styleNumber)</b><br /> These messages (plus <a class="message" @@ -2457,6 +2467,21 @@ struct Sci_TextToFind { Pango antialiases text, works well with Unicode and is better supported in recent versions of GTK+ but GDK is faster. Prepend a '!' character to the font name to use Pango.</p> + <p>Sizes can be set to a whole number of points with <code>SCI_STYLESETSIZE</code> + or to a fractional point size in hundredths of a point with <code>SCI_STYLESETSIZEFRACTIONAL</code> + by multiplying the size by 100 (<code>SC_FONT_SIZE_MULTIPLIER</code>). + For example, a text size of 9.4 points is set with <code>SCI_STYLESETSIZEFRACTIONAL(<style>, 940)</code>. + </p> + <p>The weight or boldness of a font can be set with <code>SCI_STYLESETBOLD</code> + or <code>SCI_STYLESETWEIGHT</code>. The weight is a number between 1 and 999 with 1 being very light + and 999 very heavy. While any value can be used, fonts often only support between 2 and 4 weights with three weights + being common enough to have symbolic names: + <code>SC_WEIGHT_NORMAL</code> (400), + <code>SC_WEIGHT_SEMIBOLD</code> (600), and + <code>SC_WEIGHT_BOLD</code> (700). + The <code>SCI_STYLESETBOLD</code> message takes a boolean argument with 0 choosing <code>SC_WEIGHT_NORMAL</code> + and 1 <code>SC_WEIGHT_BOLD</code>. + </p> <p><b id="SCI_STYLESETUNDERLINE">SCI_STYLESETUNDERLINE(int styleNumber, bool underline)</b><br /> @@ -2983,6 +3008,8 @@ struct Sci_TextToFind { <a class="message" href="#SCI_GETBUFFEREDDRAW">SCI_GETBUFFEREDDRAW</a><br /> <a class="message" href="#SCI_SETTWOPHASEDRAW">SCI_SETTWOPHASEDRAW(bool twoPhase)</a><br /> <a class="message" href="#SCI_GETTWOPHASEDRAW">SCI_GETTWOPHASEDRAW</a><br /> + <a class="message" href="#SCI_SETTECHNOLOGY">SCI_SETTECHNOLOGY(int technology)</a><br /> + <a class="message" href="#SCI_GETTECHNOLOGY">SCI_GETTECHNOLOGY</a><br /> <a class="message" href="#SCI_SETFONTQUALITY">SCI_SETFONTQUALITY(int fontQuality)</a><br /> <a class="message" href="#SCI_GETFONTQUALITY">SCI_GETFONTQUALITY</a><br /> <a class="message" href="#SCI_SETCODEPAGE">SCI_SETCODEPAGE(int codePage)</a><br /> @@ -3046,6 +3073,13 @@ struct Sci_TextToFind { transparent mode. Two phase drawing may flicker more than single phase unless buffered drawing is on. The default is for drawing to be two phase.</p> + <p><b id="SCI_SETTECHNOLOGY">SCI_SETTECHNOLOGY(int technology)</b><br /> + <b id="SCI_GETTECHNOLOGY">SCI_GETTECHNOLOGY</b><br /> + The technology property allows choosing between different drawing APIs and options. + On most platforms, the only choice is <code>SC_TECHNOLOGY_DEFAULT</code> (0). + On Windows Vista or later, <code>SC_TECHNOLOGY_DIRECTWRITE</code> (1) + can be chosen to use the Direct2D and DirectWrite APIs for higher quality antialiased drawing.</p> + <p><b id="SCI_SETFONTQUALITY">SCI_SETFONTQUALITY(int fontQuality)</b><br /> <b id="SCI_GETFONTQUALITY">SCI_GETFONTQUALITY</b><br /> Manage font quality (antialiasing method). Currently, the following values are available on Windows: diff --git a/gtk/PlatGTK.cxx b/gtk/PlatGTK.cxx index 8fe55145a..ffb04d005 100644 --- a/gtk/PlatGTK.cxx +++ b/gtk/PlatGTK.cxx @@ -92,7 +92,7 @@ enum encodingType { singleByte, UTF8, dbcs}; struct LOGFONT { int size; - bool bold; + int weight; bool italic; int characterSet; char faceName[300]; @@ -443,10 +443,10 @@ static void GenerateFontSpecStrings(const char *fontName, int characterSet, #endif -static void SetLogFont(LOGFONT &lf, const char *faceName, int characterSet, int size, bool bold, bool italic) { +static void SetLogFont(LOGFONT &lf, const char *faceName, int characterSet, float size, int weight, bool italic) { memset(&lf, 0, sizeof(lf)); lf.size = size; - lf.bold = bold; + lf.weight = weight; lf.italic = italic; lf.characterSet = characterSet; strncpy(lf.faceName, faceName, sizeof(lf.faceName) - 1); @@ -457,13 +457,13 @@ static void SetLogFont(LOGFONT &lf, const char *faceName, int characterSet, int * If one font is the same as another, its hash will be the same, but if the hash is the * same then they may still be different. */ -static int HashFont(const char *faceName, int characterSet, int size, bool bold, bool italic) { +static int HashFont(const FontParameters &fp) { return - size ^ - (characterSet << 10) ^ - (bold ? 0x10000000 : 0) ^ - (italic ? 0x20000000 : 0) ^ - faceName[0]; + static_cast<int>(fp.size+0.5) ^ + (fp.characterSet << 10) ^ + ((fp.weight / 100) << 12) ^ + (fp.italic ? 0x20000000 : 0) ^ + fp.faceName[0]; } class FontCached : Font { @@ -471,35 +471,34 @@ class FontCached : Font { int usage; LOGFONT lf; int hash; - FontCached(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_); + FontCached(const FontParameters &fp); ~FontCached() {} - bool SameAs(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_); + bool SameAs(const FontParameters &fp); virtual void Release(); - static FontID CreateNewFont(const char *fontName, int characterSet, - int size, bool bold, bool italic); + static FontID CreateNewFont(const FontParameters &fp); static FontCached *first; public: - static FontID FindOrCreate(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_); + static FontID FindOrCreate(const FontParameters &fp); static void ReleaseId(FontID fid_); }; FontCached *FontCached::first = 0; -FontCached::FontCached(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_) : +FontCached::FontCached(const FontParameters &fp) : next(0), usage(0), hash(0) { - ::SetLogFont(lf, faceName_, characterSet_, size_, bold_, italic_); - hash = HashFont(faceName_, characterSet_, size_, bold_, italic_); - fid = CreateNewFont(faceName_, characterSet_, size_, bold_, italic_); + ::SetLogFont(lf, fp.faceName, fp.characterSet, fp.size, fp.weight, fp.italic); + hash = HashFont(fp); + fid = CreateNewFont(fp); usage = 1; } -bool FontCached::SameAs(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_) { +bool FontCached::SameAs(const FontParameters &fp) { return - lf.size == size_ && - lf.bold == bold_ && - lf.italic == italic_ && - lf.characterSet == characterSet_ && - 0 == strcmp(lf.faceName, faceName_); + lf.size == fp.size && + lf.weight == fp.weight && + lf.italic == fp.italic && + lf.characterSet == fp.characterSet && + 0 == strcmp(lf.faceName, fp.faceName); } void FontCached::Release() { @@ -508,19 +507,19 @@ void FontCached::Release() { fid = 0; } -FontID FontCached::FindOrCreate(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_) { +FontID FontCached::FindOrCreate(const FontParameters &fp) { FontID ret = 0; FontMutexLock(); - int hashFind = HashFont(faceName_, characterSet_, size_, bold_, italic_); + int hashFind = HashFont(fp); for (FontCached *cur = first; cur; cur = cur->next) { if ((cur->hash == hashFind) && - cur->SameAs(faceName_, characterSet_, size_, bold_, italic_)) { + cur->SameAs(fp)) { cur->usage++; ret = cur->fid; } } if (ret == 0) { - FontCached *fc = new FontCached(faceName_, characterSet_, size_, bold_, italic_); + FontCached *fc = new FontCached(fp); if (fc) { fc->next = first; first = fc; @@ -560,16 +559,15 @@ static GdkFont *LoadFontOrSet(const char *fontspec, int characterSet) { } #endif -FontID FontCached::CreateNewFont(const char *fontName, int characterSet, - int size, bool bold, bool italic) { - if (fontName[0] == '!') { +FontID FontCached::CreateNewFont(const FontParameters &fp) { + if (fp.faceName[0] == '!') { PangoFontDescription *pfd = pango_font_description_new(); if (pfd) { - pango_font_description_set_family(pfd, fontName+1); - pango_font_description_set_size(pfd, size * PANGO_SCALE); - pango_font_description_set_weight(pfd, bold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL); - pango_font_description_set_style(pfd, italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL); - return new FontHandle(pfd, characterSet); + pango_font_description_set_family(pfd, fp.faceName+1); + pango_font_description_set_size(pfd, pango_units_from_double(fp.size)); + pango_font_description_set_weight(pfd, static_cast<PangoWeight>(fp.weight)); + pango_font_description_set_style(pfd, fp.italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL); + return new FontHandle(pfd, fp.characterSet); } } @@ -636,7 +634,7 @@ FontID FontCached::CreateNewFont(const char *fontName, int characterSet, sizeof(fontspec) - 1, spec, foundary, faceName, - bold ? "-bold" : "-medium", + (weight > 400) ? "-bold" : "-medium", italic ? "-i" : "-r", size * 10, charset); @@ -652,7 +650,7 @@ FontID FontCached::CreateNewFont(const char *fontName, int characterSet, sizeof(fontspec) - 1, ",%s%s%s-o-*-*-*-%0d-*-*-*-*-%s", foundary, faceName, - bold ? "-bold" : "-medium", + (weight > 400) ? "-bold" : "-medium", size * 10, charset); } @@ -686,7 +684,7 @@ FontID FontCached::CreateNewFont(const char *fontName, int characterSet, sizeof(fontspec) - 1, "%s%s%s%s-*-*-*-%0d-*-*-*-*-%s", foundary, faceName, - bold ? "-bold" : "-medium", + (weight > 400) ? "-bold" : "-medium", italic ? "-i" : "-r", size * 10, charset); @@ -697,7 +695,7 @@ FontID FontCached::CreateNewFont(const char *fontName, int characterSet, sizeof(fontspec) - 1, "%s%s%s%s-*-*-*-%0d-*-*-*-*-%s", foundary, faceName, - bold ? "-bold" : "-medium", + (weight > 400) ? "-bold" : "-medium", italic ? "-o" : "-r", size * 10, charset); @@ -727,10 +725,9 @@ Font::Font() : fid(0) {} Font::~Font() {} -void Font::Create(const char *faceName, int characterSet, int size, - bool bold, bool italic, int) { +void Font::Create(const FontParameters &fp) { Release(); - fid = FontCached::FindOrCreate(faceName, characterSet, size, bold, italic); + fid = FontCached::FindOrCreate(fp); } void Font::Release() { @@ -790,19 +787,19 @@ public: void Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back); void Copy(PRectangle rc, Point from, Surface &surfaceSource); - void DrawTextBase(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore); - void DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back); - void DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back); - void DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore); - void MeasureWidths(Font &font_, const char *s, int len, int *positions); - int WidthText(Font &font_, const char *s, int len); - int WidthChar(Font &font_, char ch); - int Ascent(Font &font_); - int Descent(Font &font_); - int InternalLeading(Font &font_); - int ExternalLeading(Font &font_); - int Height(Font &font_); - int AverageCharWidth(Font &font_); + void DrawTextBase(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore); + void DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back); + void DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back); + void DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore); + void MeasureWidths(Font &font_, const char *s, int len, XYPOSITION *positions); + XYPOSITION WidthText(Font &font_, const char *s, int len); + XYPOSITION WidthChar(Font &font_, char ch); + XYPOSITION Ascent(Font &font_); + XYPOSITION Descent(Font &font_); + XYPOSITION InternalLeading(Font &font_); + XYPOSITION ExternalLeading(Font &font_); + XYPOSITION Height(Font &font_); + XYPOSITION AverageCharWidth(Font &font_); int SetPalette(Palette *pal, bool inBackGround); void SetClip(PRectangle rc); @@ -1579,7 +1576,7 @@ static size_t UTF8CharLength(const char *s) { const int maxLengthTextRun = 10000; -void SurfaceImpl::DrawTextBase(PRectangle rc, Font &font_, int ybase, const char *s, int len, +void SurfaceImpl::DrawTextBase(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore) { PenColour(fore); #ifdef USE_CAIRO @@ -1587,7 +1584,7 @@ void SurfaceImpl::DrawTextBase(PRectangle rc, Font &font_, int ybase, const char #else if (gc && drawable) { #endif - int xText = rc.left; + XYPOSITION xText = rc.left; if (PFont(font_)->pfd) { char *utfForm = 0; if (et == UTF8) { @@ -1678,20 +1675,20 @@ void SurfaceImpl::DrawTextBase(PRectangle rc, Font &font_, int ybase, const char } } -void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len, +void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back) { FillRectangle(rc, back); DrawTextBase(rc, font_, ybase, s, len, fore); } // On GTK+, exactly same as DrawTextNoClip -void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, +void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back) { FillRectangle(rc, back); DrawTextBase(rc, font_, ybase, s, len, fore); } -void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, +void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore) { // Avoid drawing spaces in transparent mode for (int i=0;i<len;i++) { @@ -1708,9 +1705,9 @@ class ClusterIterator { int lenPositions; public: bool finished; - int positionStart; - int position; - int distance; + XYPOSITION positionStart; + XYPOSITION position; + XYPOSITION distance; int curIndex; ClusterIterator(PangoLayout *layout, int len) : lenPositions(len), finished(false), positionStart(0), position(0), distance(0), curIndex(0) { @@ -1725,18 +1722,18 @@ public: positionStart = position; if (pango_layout_iter_next_cluster(iter)) { pango_layout_iter_get_cluster_extents(iter, NULL, &pos); - position = PANGO_PIXELS(pos.x); + position = pango_units_to_double(pos.x); curIndex = pango_layout_iter_get_index(iter); } else { finished = true; - position = PANGO_PIXELS(pos.x + pos.width); + position = pango_units_to_double(pos.x + pos.width); curIndex = lenPositions; } distance = position - positionStart; } }; -void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positions) { +void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, XYPOSITION *positions) { if (font_.GetID()) { const int lenPositions = len; if (PFont(font_)->pfd) { @@ -1892,7 +1889,7 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positi } } -int SurfaceImpl::WidthText(Font &font_, const char *s, int len) { +XYPOSITION SurfaceImpl::WidthText(Font &font_, const char *s, int len) { if (font_.GetID()) { if (PFont(font_)->pfd) { char *utfForm = 0; @@ -1921,7 +1918,7 @@ int SurfaceImpl::WidthText(Font &font_, const char *s, int len) { #endif pango_layout_line_get_extents(pangoLine, NULL, &pos); delete []utfForm; - return PANGO_PIXELS(pos.width); + return pango_units_to_double(pos.width); } #ifndef DISABLE_GDK_FONT if (et == UTF8) { @@ -1941,7 +1938,7 @@ int SurfaceImpl::WidthText(Font &font_, const char *s, int len) { } } -int SurfaceImpl::WidthChar(Font &font_, char ch) { +XYPOSITION SurfaceImpl::WidthChar(Font &font_, char ch) { if (font_.GetID()) { if (PFont(font_)->pfd) { return WidthText(font_, &ch, 1); @@ -1973,7 +1970,7 @@ const char sizeString[] = "`~!@#$%^&*()-_=+\\|[]{};:\"\'<,>.?/1234567890" "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; #endif -int SurfaceImpl::Ascent(Font &font_) { +XYPOSITION SurfaceImpl::Ascent(Font &font_) { if (!(font_.GetID())) return 1; #ifdef FAST_WAY @@ -1983,7 +1980,7 @@ int SurfaceImpl::Ascent(Font &font_) { PangoFontMetrics *metrics = pango_context_get_metrics(pcontext, PFont(font_)->pfd, pango_context_get_language(pcontext)); PFont(font_)->ascent = - PANGO_PIXELS(pango_font_metrics_get_ascent(metrics)); + pango_units_to_double(pango_font_metrics_get_ascent(metrics)); pango_font_metrics_unref(metrics); ascent = PFont(font_)->ascent; } @@ -2011,7 +2008,7 @@ int SurfaceImpl::Ascent(Font &font_) { #endif } -int SurfaceImpl::Descent(Font &font_) { +XYPOSITION SurfaceImpl::Descent(Font &font_) { if (!(font_.GetID())) return 1; #ifdef FAST_WAY @@ -2019,7 +2016,7 @@ int SurfaceImpl::Descent(Font &font_) { if (PFont(font_)->pfd) { PangoFontMetrics *metrics = pango_context_get_metrics(pcontext, PFont(font_)->pfd, pango_context_get_language(pcontext)); - int descent = PANGO_PIXELS(pango_font_metrics_get_descent(metrics)); + int descent = pango_units_to_double(pango_font_metrics_get_descent(metrics)); pango_font_metrics_unref(metrics); return descent; } @@ -2042,19 +2039,19 @@ int SurfaceImpl::Descent(Font &font_) { #endif } -int SurfaceImpl::InternalLeading(Font &) { +XYPOSITION SurfaceImpl::InternalLeading(Font &) { return 0; } -int SurfaceImpl::ExternalLeading(Font &) { +XYPOSITION SurfaceImpl::ExternalLeading(Font &) { return 0; } -int SurfaceImpl::Height(Font &font_) { +XYPOSITION SurfaceImpl::Height(Font &font_) { return Ascent(font_) + Descent(font_); } -int SurfaceImpl::AverageCharWidth(Font &font_) { +XYPOSITION SurfaceImpl::AverageCharWidth(Font &font_) { return WidthChar(font_, 'n'); } @@ -2086,8 +2083,8 @@ void SurfaceImpl::SetDBCSMode(int codePage) { et = dbcs; } -Surface *Surface::Allocate() { - return new SurfaceImpl; +Surface *Surface::Allocate(int) { + return new SurfaceImpl(); } Window::~Window() {} @@ -2307,7 +2304,7 @@ public: } } virtual void SetFont(Font &font); - virtual void Create(Window &parent, int ctrlID, Point location_, int lineHeight_, bool unicodeMode_); + virtual void Create(Window &parent, int ctrlID, Point location_, int lineHeight_, bool unicodeMode_, int technology_); virtual void SetAverageCharWidth(int width); virtual void SetVisibleRows(int rows); virtual int GetVisibleRows() const; @@ -2396,7 +2393,7 @@ static void StyleSet(GtkWidget *w, GtkStyle*, void*) { #endif } -void ListBoxX::Create(Window &, int, Point, int, bool) { +void ListBoxX::Create(Window &, int, Point, int, bool, int) { wid = gtk_window_new(GTK_WINDOW_POPUP); GtkWidget *frame = gtk_frame_new(NULL); @@ -2838,7 +2835,7 @@ void Menu::Show(Point pt, Window &) { pt.y = screenHeight - requisition.height; } gtk_menu_popup(widget, NULL, NULL, MenuPositionFunc, - reinterpret_cast<void *>((pt.y << 16) | pt.x), 0, + reinterpret_cast<void *>((static_cast<int>(pt.y) << 16) | static_cast<int>(pt.x)), 0, gtk_get_current_event_time()); } diff --git a/gtk/ScintillaGTK.cxx b/gtk/ScintillaGTK.cxx index 0932c6e3b..efb0e0cd5 100644 --- a/gtk/ScintillaGTK.cxx +++ b/gtk/ScintillaGTK.cxx @@ -584,7 +584,7 @@ void ScintillaGTK::UnMapThis() { #else GTK_WIDGET_UNSET_FLAGS(PWidget(wMain), GTK_MAPPED); #endif - DropGraphics(); + DropGraphics(false); gdk_window_hide(PWindow(wMain)); gtk_widget_unmap(PWidget(wText)); gtk_widget_unmap(PWidget(scrollbarh)); @@ -1112,7 +1112,7 @@ void ScintillaGTK::SyncPaint(PRectangle rc) { PRectangle rcClient = GetClientRectangle(); paintingAllText = rcPaint.Contains(rcClient); if (PWindow(wText)) { - Surface *sw = Surface::Allocate(); + Surface *sw = Surface::Allocate(SC_TECHNOLOGY_DEFAULT); if (sw) { #if GTK_CHECK_VERSION(3,0,0) cairo_t *cr = gdk_cairo_create(PWindow(wText)); @@ -2473,7 +2473,7 @@ gboolean ScintillaGTK::DrawTextThis(cairo_t *cr) { rcPaint.bottom = y2; PRectangle rcClient = GetClientRectangle(); paintingAllText = rcPaint.Contains(rcClient); - Surface *surfaceWindow = Surface::Allocate(); + Surface *surfaceWindow = Surface::Allocate(SC_TECHNOLOGY_DEFAULT); if (surfaceWindow) { surfaceWindow->Init(cr, PWidget(wText)); Paint(surfaceWindow, rcPaint); @@ -2831,7 +2831,7 @@ gboolean ScintillaGTK::PressCT(GtkWidget *widget, GdkEventButton *event, Scintil gboolean ScintillaGTK::DrawCT(GtkWidget *widget, cairo_t *cr, CallTip *ctip) { try { - Surface *surfaceWindow = Surface::Allocate(); + Surface *surfaceWindow = Surface::Allocate(SC_TECHNOLOGY_DEFAULT); if (surfaceWindow) { surfaceWindow->Init(cr, widget); surfaceWindow->SetUnicodeMode(SC_CP_UTF8 == ctip->codePage); diff --git a/include/Platform.h b/include/Platform.h index b0f3de0dc..499e78e5d 100644 --- a/include/Platform.h +++ b/include/Platform.h @@ -59,6 +59,10 @@ namespace Scintilla { #endif +typedef float XYPOSITION; +typedef double XYACCUMULATOR; +//#define XYPOSITION int + // Underlying the implementation of the platform classes are platform specific types. // Sometimes these need to be passed around by client code so they are defined here @@ -76,10 +80,10 @@ typedef void *IdlerID; */ class Point { public: - int x; - int y; + XYPOSITION x; + XYPOSITION y; - explicit Point(int x_=0, int y_=0) : x(x_), y(y_) { + explicit Point(XYPOSITION x_=0, XYPOSITION y_=0) : x(x_), y(y_) { } // Other automatically defined methods (assignment, copy constructor, destructor) are fine @@ -94,12 +98,12 @@ public: */ class PRectangle { public: - int left; - int top; - int right; - int bottom; + XYPOSITION left; + XYPOSITION top; + XYPOSITION right; + XYPOSITION bottom; - PRectangle(int left_=0, int top_=0, int right_=0, int bottom_ = 0) : + PRectangle(XYPOSITION left_=0, XYPOSITION top_=0, XYPOSITION right_=0, XYPOSITION bottom_ = 0) : left(left_), top(top_), right(right_), bottom(bottom_) { } @@ -121,14 +125,14 @@ public: return (right > other.left) && (left < other.right) && (bottom > other.top) && (top < other.bottom); } - void Move(int xDelta, int yDelta) { + void Move(XYPOSITION xDelta, XYPOSITION yDelta) { left += xDelta; top += yDelta; right += xDelta; bottom += yDelta; } - int Width() { return right - left; } - int Height() { return bottom - top; } + XYPOSITION Width() { return right - left; } + XYPOSITION Height() { return bottom - top; } bool Empty() { return (Height() <= 0) || (Width() <= 0); } @@ -287,6 +291,37 @@ public: /** * Font management. */ + +struct FontParameters { + const char *faceName; + float size; + int weight; + bool italic; + int extraFontFlag; + int technology; + int characterSet; + + FontParameters( + const char *faceName_, + float size_=10, + int weight_=400, + bool italic_=false, + int extraFontFlag_=0, + int technology_=0, + int characterSet_=0) : + + faceName(faceName_), + size(size_), + weight(weight_), + italic(italic_), + extraFontFlag(extraFontFlag_), + technology(technology_), + characterSet(characterSet_) + { + } + +}; + class Font { protected: FontID fid; @@ -300,8 +335,7 @@ public: Font(); virtual ~Font(); - virtual void Create(const char *faceName, int characterSet, int size, - bool bold, bool italic, int extraFontFlag=0); + virtual void Create(const FontParameters &fp); virtual void Release(); FontID GetID() { return fid; } @@ -325,7 +359,7 @@ private: public: Surface() {} virtual ~Surface() {} - static Surface *Allocate(); + static Surface *Allocate(int technology); virtual void Init(WindowID wid)=0; virtual void Init(SurfaceID sid, WindowID wid)=0; @@ -349,18 +383,18 @@ public: virtual void Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back)=0; virtual void Copy(PRectangle rc, Point from, Surface &surfaceSource)=0; - virtual void DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back)=0; - virtual void DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back)=0; - virtual void DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore)=0; - virtual void MeasureWidths(Font &font_, const char *s, int len, int *positions)=0; - virtual int WidthText(Font &font_, const char *s, int len)=0; - virtual int WidthChar(Font &font_, char ch)=0; - virtual int Ascent(Font &font_)=0; - virtual int Descent(Font &font_)=0; - virtual int InternalLeading(Font &font_)=0; - virtual int ExternalLeading(Font &font_)=0; - virtual int Height(Font &font_)=0; - virtual int AverageCharWidth(Font &font_)=0; + virtual void DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back)=0; + virtual void DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back)=0; + virtual void DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore)=0; + virtual void MeasureWidths(Font &font_, const char *s, int len, XYPOSITION *positions)=0; + virtual XYPOSITION WidthText(Font &font_, const char *s, int len)=0; + virtual XYPOSITION WidthChar(Font &font_, char ch)=0; + virtual XYPOSITION Ascent(Font &font_)=0; + virtual XYPOSITION Descent(Font &font_)=0; + virtual XYPOSITION InternalLeading(Font &font_)=0; + virtual XYPOSITION ExternalLeading(Font &font_)=0; + virtual XYPOSITION Height(Font &font_)=0; + virtual XYPOSITION AverageCharWidth(Font &font_)=0; virtual int SetPalette(Palette *pal, bool inBackGround)=0; virtual void SetClip(PRectangle rc)=0; @@ -439,7 +473,7 @@ public: static ListBox *Allocate(); virtual void SetFont(Font &font)=0; - virtual void Create(Window &parent, int ctrlID, Point location, int lineHeight_, bool unicodeMode_)=0; + virtual void Create(Window &parent, int ctrlID, Point location, int lineHeight_, bool unicodeMode_, int technology_)=0; virtual void SetAverageCharWidth(int width)=0; virtual void SetVisibleRows(int rows)=0; virtual int GetVisibleRows() const=0; diff --git a/include/Scintilla.h b/include/Scintilla.h index 34e4f793d..c8ffba04e 100644 --- a/include/Scintilla.h +++ b/include/Scintilla.h @@ -221,6 +221,14 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_STYLEGETCHANGEABLE 2492 #define SCI_STYLEGETHOTSPOT 2493 #define SCI_STYLESETCASE 2060 +#define SC_FONT_SIZE_MULTIPLIER 100 +#define SCI_STYLESETSIZEFRACTIONAL 2061 +#define SCI_STYLEGETSIZEFRACTIONAL 2062 +#define SC_WEIGHT_NORMAL 400 +#define SC_WEIGHT_SEMIBOLD 600 +#define SC_WEIGHT_BOLD 700 +#define SCI_STYLESETWEIGHT 2063 +#define SCI_STYLEGETWEIGHT 2064 #define SCI_STYLESETCHARACTERSET 2066 #define SCI_STYLESETHOTSPOT 2409 #define SCI_SETSELFORE 2067 @@ -819,6 +827,10 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_REGISTERRGBAIMAGE 2627 #define SCI_SCROLLTOSTART 2628 #define SCI_SCROLLTOEND 2629 +#define SC_TECHNOLOGY_DEFAULT 0 +#define SC_TECHNOLOGY_DIRECTWRITE 1 +#define SCI_SETTECHNOLOGY 2630 +#define SCI_GETTECHNOLOGY 2631 #define SCI_STARTRECORD 3001 #define SCI_STOPRECORD 3002 #define SCI_SETLEXER 4001 diff --git a/include/Scintilla.iface b/include/Scintilla.iface index 9530f4292..23da6d5b5 100644 --- a/include/Scintilla.iface +++ b/include/Scintilla.iface @@ -482,6 +482,25 @@ get bool StyleGetHotSpot=2493(int style,) # Set a style to be mixed case, or to force upper or lower case. set void StyleSetCase=2060(int style, int caseForce) +val SC_FONT_SIZE_MULTIPLIER=100 + +# Set the size of characters of a style. Size is in points multiplied by 100. +set void StyleSetSizeFractional=2061(int style, int caseForce) + +# Get the size of characters of a style in points multiplied by 100 +get int StyleGetSizeFractional=2062(int style,) + +enu FontWeight=SC_WEIGHT_ +val SC_WEIGHT_NORMAL=400 +val SC_WEIGHT_SEMIBOLD=600 +val SC_WEIGHT_BOLD=700 + +# Set the weight of characters of a style. +set void StyleSetWeight=2063(int style, int weight) + +# Get the weight of characters of a style. +get int StyleGetWeight=2064(int style,) + # Set the character set of the font in a style. set void StyleSetCharacterSet=2066(int style, int characterSet) @@ -2175,6 +2194,15 @@ fun void ScrollToStart=2628(,) # Scroll to end of document. fun void ScrollToEnd=2629(,) +val SC_TECHNOLOGY_DEFAULT=0 +val SC_TECHNOLOGY_DIRECTWRITE=1 + +# Set the technolgy used. +set void SetTechnology=2630(int technology,) + +# Get the tech. +get int GetTechnology=2631(,) + # Start notifying the container of all key presses and commands. fun void StartRecord=3001(,) diff --git a/src/AutoComplete.cxx b/src/AutoComplete.cxx index f6a291fe9..2752ef0c9 100644 --- a/src/AutoComplete.cxx +++ b/src/AutoComplete.cxx @@ -50,11 +50,11 @@ bool AutoComplete::Active() const { void AutoComplete::Start(Window &parent, int ctrlID, int position, Point location, int startLen_, - int lineHeight, bool unicodeMode) { + int lineHeight, bool unicodeMode, int technology) { if (active) { Cancel(); } - lb->Create(parent, ctrlID, location, lineHeight, unicodeMode); + lb->Create(parent, ctrlID, location, lineHeight, unicodeMode, technology); lb->Clear(); active = true; startLen = startLen_; diff --git a/src/AutoComplete.h b/src/AutoComplete.h index f48cb0551..aefab120a 100644 --- a/src/AutoComplete.h +++ b/src/AutoComplete.h @@ -40,7 +40,7 @@ public: /// Display the auto completion list positioned to be near a character position void Start(Window &parent, int ctrlID, int position, Point location, - int startLen_, int lineHeight, bool unicodeMode); + int startLen_, int lineHeight, bool unicodeMode, int technology); /// The stop chars are characters which, when typed, cause the auto completion list to disappear void SetStopChars(const char *stopChars_); diff --git a/src/CallTip.cxx b/src/CallTip.cxx index cdc30fcbc..0e1e80cc1 100644 --- a/src/CallTip.cxx +++ b/src/CallTip.cxx @@ -255,14 +255,15 @@ void CallTip::MouseClick(Point pt) { PRectangle CallTip::CallTipStart(int pos, Point pt, const char *defn, const char *faceName, int size, - int codePage_, int characterSet, Window &wParent) { + int codePage_, int characterSet, + int technology, Window &wParent) { clickPlace = 0; delete []val; val = 0; val = new char[strlen(defn) + 1]; strcpy(val, defn); codePage = codePage_; - Surface *surfaceMeasure = Surface::Allocate(); + Surface *surfaceMeasure = Surface::Allocate(technology); if (!surfaceMeasure) return PRectangle(); surfaceMeasure->Init(wParent.GetID()); @@ -273,7 +274,8 @@ PRectangle CallTip::CallTipStart(int pos, Point pt, const char *defn, inCallTipMode = true; posStartCallTip = pos; int deviceHeight = surfaceMeasure->DeviceHeightFont(size); - font.Create(faceName, characterSet, deviceHeight, false, false); + FontParameters fp(faceName, deviceHeight / SC_FONT_SIZE_MULTIPLIER, SC_WEIGHT_NORMAL, false, 0, technology, characterSet); + font.Create(fp); // Look for multiple lines in the text // Only support \n here - simply means container must avoid \r! int numLines = 1; diff --git a/src/CallTip.h b/src/CallTip.h index a9ba82eb8..e437f3309 100644 --- a/src/CallTip.h +++ b/src/CallTip.h @@ -62,7 +62,7 @@ public: /// Setup the calltip and return a rectangle of the area required. PRectangle CallTipStart(int pos, Point pt, const char *defn, const char *faceName, int size, int codePage_, - int characterSet, Window &wParent); + int characterSet, int technology, Window &wParent); void CallTipCancel(); diff --git a/src/Editor.cxx b/src/Editor.cxx index 347f27318..1257ac4b0 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -102,7 +102,8 @@ Editor::Editor() { ctrlID = 0; stylesValid = false; - + technology = SC_TECHNOLOGY_DEFAULT; + printMagnification = 0; printColourMode = SC_PRINT_NORMAL; printWrapState = eWrapWord; @@ -168,11 +169,11 @@ Editor::Editor() { additionalCaretsVisible = true; virtualSpaceOptions = SCVS_NONE; - pixmapLine = Surface::Allocate(); - pixmapSelMargin = Surface::Allocate(); - pixmapSelPattern = Surface::Allocate(); - pixmapIndentGuide = Surface::Allocate(); - pixmapIndentGuideHighlight = Surface::Allocate(); + pixmapLine = 0; + pixmapSelMargin = 0; + pixmapSelPattern = 0; + pixmapIndentGuide = 0; + pixmapIndentGuideHighlight = 0; targetStart = 0; targetEnd = 0; @@ -226,12 +227,7 @@ Editor::~Editor() { pdoc->RemoveWatcher(this, 0); pdoc->Release(); pdoc = 0; - DropGraphics(); - delete pixmapLine; - delete pixmapSelMargin; - delete pixmapSelPattern; - delete pixmapIndentGuide; - delete pixmapIndentGuideHighlight; + DropGraphics(true); } void Editor::Finalise() { @@ -239,17 +235,50 @@ void Editor::Finalise() { CancelModes(); } -void Editor::DropGraphics() { - pixmapLine->Release(); - pixmapSelMargin->Release(); - pixmapSelPattern->Release(); - pixmapIndentGuide->Release(); - pixmapIndentGuideHighlight->Release(); +void Editor::DropGraphics(bool freeObjects) { + if (freeObjects) { + delete pixmapLine; + pixmapLine = 0; + delete pixmapSelMargin; + pixmapSelMargin = 0; + delete pixmapSelPattern; + pixmapSelPattern = 0; + delete pixmapIndentGuide; + pixmapIndentGuide = 0; + delete pixmapIndentGuideHighlight; + pixmapIndentGuideHighlight = 0; + } else { + if (pixmapLine) + pixmapLine->Release(); + if (pixmapSelMargin) + pixmapSelMargin->Release(); + if (pixmapSelPattern) + pixmapSelPattern->Release(); + if (pixmapIndentGuide) + pixmapIndentGuide->Release(); + if (pixmapIndentGuideHighlight) + pixmapIndentGuideHighlight->Release(); + } +} + +void Editor::AllocateGraphics() { + if (!pixmapLine) + pixmapLine = Surface::Allocate(technology); + if (!pixmapSelMargin) + pixmapSelMargin = Surface::Allocate(technology); + if (!pixmapSelPattern) + pixmapSelPattern = Surface::Allocate(technology); + if (!pixmapIndentGuide) + pixmapIndentGuide = Surface::Allocate(technology); + if (!pixmapIndentGuideHighlight) + pixmapIndentGuideHighlight = Surface::Allocate(technology); } void Editor::InvalidateStyleData() { stylesValid = false; - DropGraphics(); + vs.technology = technology; + DropGraphics(false); + AllocateGraphics(); palette.Release(); llc.Invalidate(LineLayout::llInvalid); posCache.Clear(); @@ -2216,7 +2245,7 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou // Layout the line, determining the position of each character, // with an extra element at the end for the end of the line. int startseg = 0; // Start of the current segment, in char. number - int startsegx = 0; // Start of the current segment, in pixels + XYACCUMULATOR startsegx = 0; // Start of the current segment, in pixels ll->positions[0] = 0; unsigned int tabWidth = vstyle.spaceWidth * pdoc->tabInChars; bool lastSegItalics = false; @@ -2237,7 +2266,7 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou if (vstyle.styles[ll->styles[charInLine]].visible) { if (isControl) { if (ll->chars[charInLine] == '\t') { - ll->positions[charInLine + 1] = ((((startsegx + 2) / + ll->positions[charInLine + 1] = ((((static_cast<int>(startsegx) + 2) / tabWidth) + 1) * tabWidth) - startsegx; } else if (controlCharSymbol < 32) { if (ctrlCharWidth[ll->chars[charInLine]] == 0) { @@ -2902,8 +2931,10 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis // draw strings that are completely past the right side of the window. if ((rcSegment.left <= rcLine.right) && (rcSegment.right >= rcLine.left)) { // Clip to line rectangle, since may have a huge position which will not work with some platforms - rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left); - rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right); + if (rcSegment.left < rcLine.left) + rcSegment.left = rcLine.left; + if (rcSegment.right > rcLine.right) + rcSegment.right = rcLine.right; int styleMain = ll->styles[i]; const int inSelection = hideSelection ? 0 : sel.CharacterInSelection(iDoc); @@ -3379,7 +3410,7 @@ void Editor::DrawCarets(Surface *surface, ViewStyle &vsDraw, int lineDoc, int xS const int spaceWidth = static_cast<int>(vsDraw.styles[ll->EndLineStyle()].spaceWidth); const int virtualOffset = posCaret.VirtualSpace() * spaceWidth; if (ll->InLine(offset, subLine) && offset <= ll->numCharsBeforeEOL) { - int xposCaret = ll->positions[offset] + virtualOffset - ll->positions[ll->LineStart(subLine)]; + XYPOSITION xposCaret = ll->positions[offset] + virtualOffset - ll->positions[ll->LineStart(subLine)]; if (ll->wrapIndent != 0) { int lineStart = ll->LineStart(subLine); if (lineStart != 0) // Wrapped @@ -3924,7 +3955,7 @@ void Editor::SetScrollBars() { } void Editor::ChangeSize() { - DropGraphics(); + DropGraphics(false); SetScrollBars(); if (wrapState != eWrapNone) { PRectangle rcTextArea = GetClientRectangle(); @@ -6979,7 +7010,10 @@ void Editor::StyleSetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam vs.styles[wParam].back.desired = ColourDesired(lParam); break; case SCI_STYLESETBOLD: - vs.styles[wParam].bold = lParam != 0; + vs.styles[wParam].weight = lParam != 0 ? SC_WEIGHT_BOLD : SC_WEIGHT_NORMAL; + break; + case SCI_STYLESETWEIGHT: + vs.styles[wParam].weight = lParam; break; case SCI_STYLESETITALIC: vs.styles[wParam].italic = lParam != 0; @@ -6988,6 +7022,9 @@ void Editor::StyleSetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam vs.styles[wParam].eolFilled = lParam != 0; break; case SCI_STYLESETSIZE: + vs.styles[wParam].size = lParam * SC_FONT_SIZE_MULTIPLIER; + break; + case SCI_STYLESETSIZEFRACTIONAL: vs.styles[wParam].size = lParam; break; case SCI_STYLESETFONT: @@ -7025,12 +7062,16 @@ sptr_t Editor::StyleGetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lPar case SCI_STYLEGETBACK: return vs.styles[wParam].back.desired.AsLong(); case SCI_STYLEGETBOLD: - return vs.styles[wParam].bold ? 1 : 0; + return vs.styles[wParam].weight > SC_WEIGHT_NORMAL; + case SCI_STYLEGETWEIGHT: + return vs.styles[wParam].weight; case SCI_STYLEGETITALIC: return vs.styles[wParam].italic ? 1 : 0; case SCI_STYLEGETEOLFILLED: return vs.styles[wParam].eolFilled ? 1 : 0; case SCI_STYLEGETSIZE: + return vs.styles[wParam].size / SC_FONT_SIZE_MULTIPLIER; + case SCI_STYLEGETSIZEFRACTIONAL: return vs.styles[wParam].size; case SCI_STYLEGETFONT: if (!vs.styles[wParam].fontName) @@ -8148,9 +8189,11 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_STYLESETFORE: case SCI_STYLESETBACK: case SCI_STYLESETBOLD: + case SCI_STYLESETWEIGHT: case SCI_STYLESETITALIC: case SCI_STYLESETEOLFILLED: case SCI_STYLESETSIZE: + case SCI_STYLESETSIZEFRACTIONAL: case SCI_STYLESETFONT: case SCI_STYLESETUNDERLINE: case SCI_STYLESETCASE: @@ -8164,9 +8207,11 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_STYLEGETFORE: case SCI_STYLEGETBACK: case SCI_STYLEGETBOLD: + case SCI_STYLEGETWEIGHT: case SCI_STYLEGETITALIC: case SCI_STYLEGETEOLFILLED: case SCI_STYLEGETSIZE: + case SCI_STYLEGETSIZEFRACTIONAL: case SCI_STYLEGETFONT: case SCI_STYLEGETUNDERLINE: case SCI_STYLEGETCASE: @@ -9202,6 +9247,13 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_GETIDENTIFIER: return GetCtrlID(); + case SCI_SETTECHNOLOGY: + // No action by default + break; + + case SCI_GETTECHNOLOGY: + return technology; + default: return DefWndProc(iMessage, wParam, lParam); } diff --git a/src/Editor.h b/src/Editor.h index f1a500b74..7a30fdf3f 100644 --- a/src/Editor.h +++ b/src/Editor.h @@ -131,6 +131,7 @@ protected: // ScintillaBase subclass needs access to much of Editor * When a style attribute is changed, this cache is flushed. */ bool stylesValid; ViewStyle vs; + int technology; Point sizeRGBAImage; Palette palette; @@ -279,7 +280,8 @@ protected: // ScintillaBase subclass needs access to much of Editor void InvalidateStyleRedraw(); virtual void RefreshColourPalette(Palette &pal, bool want); void RefreshStyleData(); - void DropGraphics(); + void DropGraphics(bool freeObjects); + void AllocateGraphics(); virtual PRectangle GetClientRectangle(); PRectangle GetTextRectangle(); @@ -574,7 +576,7 @@ private: public: AutoSurface(Editor *ed) : surf(0) { if (ed->wMain.GetID()) { - surf = Surface::Allocate(); + surf = Surface::Allocate(ed->technology); if (surf) { surf->Init(ed->wMain.GetID()); surf->SetUnicodeMode(SC_CP_UTF8 == ed->CodePage()); @@ -584,7 +586,7 @@ public: } AutoSurface(SurfaceID sid, Editor *ed) : surf(0) { if (ed->wMain.GetID()) { - surf = Surface::Allocate(); + surf = Surface::Allocate(ed->technology); if (surf) { surf->Init(sid, ed->wMain.GetID()); surf->SetUnicodeMode(SC_CP_UTF8 == ed->CodePage()); diff --git a/src/FontQuality.h b/src/FontQuality.h index 2c8d548a8..45600c35e 100644 --- a/src/FontQuality.h +++ b/src/FontQuality.h @@ -10,3 +10,6 @@ #define SC_EFF_QUALITY_NON_ANTIALIASED 1 #define SC_EFF_QUALITY_ANTIALIASED 2 #define SC_EFF_QUALITY_LCD_OPTIMIZED 3 + +#define SCWIN_TECH_GDI 0 +#define SCWIN_TECH_DIRECTWRITE 1 diff --git a/src/PositionCache.cxx b/src/PositionCache.cxx index 2105c292f..614e6b8bf 100644 --- a/src/PositionCache.cxx +++ b/src/PositionCache.cxx @@ -86,7 +86,7 @@ void LineLayout::Resize(int maxLineLength_) { indicators = new char[maxLineLength_ + 1]; // Extra position allocated as sometimes the Windows // GetTextExtentExPoint API writes an extra element. - positions = new int[maxLineLength_ + 1 + 1]; + positions = new XYPOSITION[maxLineLength_ + 1 + 1]; maxLineLength = maxLineLength_; } } @@ -503,15 +503,15 @@ PositionCacheEntry::PositionCacheEntry() : } void PositionCacheEntry::Set(unsigned int styleNumber_, const char *s_, - unsigned int len_, int *positions_, unsigned int clock_) { + unsigned int len_, XYPOSITION *positions_, unsigned int clock_) { Clear(); styleNumber = styleNumber_; len = len_; clock = clock_; if (s_ && positions_) { - positions = new short[len + (len + 1) / 2]; + positions = new XYPOSITION[len + (len + 1) / 2]; for (unsigned int i=0; i<len; i++) { - positions[i] = static_cast<short>(positions_[i]); + positions[i] = static_cast<XYPOSITION>(positions_[i]); } memcpy(reinterpret_cast<char *>(positions + len), s_, len); } @@ -530,7 +530,7 @@ void PositionCacheEntry::Clear() { } bool PositionCacheEntry::Retrieve(unsigned int styleNumber_, const char *s_, - unsigned int len_, int *positions_) const { + unsigned int len_, XYPOSITION *positions_) const { if ((styleNumber == styleNumber_) && (len == len_) && (memcmp(reinterpret_cast<char *>(positions + len), s_, len)== 0)) { for (unsigned int i=0; i<len; i++) { @@ -595,7 +595,7 @@ void PositionCache::SetSize(size_t size_) { } void PositionCache::MeasureWidths(Surface *surface, ViewStyle &vstyle, unsigned int styleNumber, - const char *s, unsigned int len, int *positions, Document *pdoc) { + const char *s, unsigned int len, XYPOSITION *positions, Document *pdoc) { allClear = false; int probe = -1; @@ -621,7 +621,7 @@ void PositionCache::MeasureWidths(Surface *surface, ViewStyle &vstyle, unsigned if (len > BreakFinder::lengthStartSubdivision) { // Break up into segments unsigned int startSegment = 0; - int xStartSegment = 0; + XYPOSITION xStartSegment = 0; while (startSegment < len) { unsigned int lenSegment = pdoc->SafeSegment(s + startSegment, len - startSegment, BreakFinder::lengthEachSubdivision); surface->MeasureWidths(vstyle.styles[styleNumber].font, s + startSegment, lenSegment, positions + startSegment); diff --git a/src/PositionCache.h b/src/PositionCache.h index c6076ea20..280446627 100644 --- a/src/PositionCache.h +++ b/src/PositionCache.h @@ -41,7 +41,7 @@ public: unsigned char *styles; int styleBitsSet; char *indicators; - int *positions; + XYPOSITION *positions; char bracePreviousStyles[2]; // Hotspot support @@ -103,13 +103,13 @@ class PositionCacheEntry { unsigned int styleNumber:8; unsigned int len:8; unsigned int clock:16; - short *positions; + XYPOSITION *positions; public: PositionCacheEntry(); ~PositionCacheEntry(); - void Set(unsigned int styleNumber_, const char *s_, unsigned int len_, int *positions_, unsigned int clock); + void Set(unsigned int styleNumber_, const char *s_, unsigned int len_, XYPOSITION *positions_, unsigned int clock); void Clear(); - bool Retrieve(unsigned int styleNumber_, const char *s_, unsigned int len_, int *positions_) const; + bool Retrieve(unsigned int styleNumber_, const char *s_, unsigned int len_, XYPOSITION *positions_) const; static int Hash(unsigned int styleNumber_, const char *s, unsigned int len); bool NewerThan(const PositionCacheEntry &other) const; void ResetClock(); @@ -155,7 +155,7 @@ public: void SetSize(size_t size_); size_t GetSize() const { return size; } void MeasureWidths(Surface *surface, ViewStyle &vstyle, unsigned int styleNumber, - const char *s, unsigned int len, int *positions, Document *pdoc); + const char *s, unsigned int len, XYPOSITION *positions, Document *pdoc); }; inline bool IsSpaceOrTab(int ch) { diff --git a/src/ScintillaBase.cxx b/src/ScintillaBase.cxx index da6b03e0d..247f34c4e 100644 --- a/src/ScintillaBase.cxx +++ b/src/ScintillaBase.cxx @@ -222,7 +222,7 @@ void ScintillaBase::AutoCompleteStart(int lenEntered, const char *list) { } } ac.Start(wMain, idAutoComplete, sel.MainCaret(), PointMainCaret(), - lenEntered, vs.lineHeight, IsUnicodeMode()); + lenEntered, vs.lineHeight, IsUnicodeMode(), technology); PRectangle rcClient = GetClientRectangle(); Point pt = LocationFromPosition(sel.MainCaret() - lenEntered); @@ -419,6 +419,7 @@ void ScintillaBase::CallTipShow(Point pt, const char *defn) { vs.styles[ctStyle].sizeZoomed, CodePage(), vs.styles[ctStyle].characterSet, + vs.technology, wMain); // If the call-tip window would be out of the client // space, adjust so it displays above the text. diff --git a/src/Style.cxx b/src/Style.cxx index fc250f0bc..0a38cd6a5 100644 --- a/src/Style.cxx +++ b/src/Style.cxx @@ -33,7 +33,7 @@ void FontAlias::ClearFont() { } bool FontSpecification::EqualTo(const FontSpecification &other) const { - return bold == other.bold && + return weight == other.weight && italic == other.italic && size == other.size && characterSet == other.characterSet && @@ -56,18 +56,18 @@ void FontMeasurements::Clear() { Style::Style() : FontSpecification() { Clear(ColourDesired(0, 0, 0), ColourDesired(0xff, 0xff, 0xff), - Platform::DefaultFontSize(), 0, SC_CHARSET_DEFAULT, - false, false, false, false, caseMixed, true, true, false); + Platform::DefaultFontSize() * SC_FONT_SIZE_MULTIPLIER, 0, SC_CHARSET_DEFAULT, + SC_WEIGHT_NORMAL, false, false, false, caseMixed, true, true, false); } Style::Style(const Style &source) : FontSpecification(), FontMeasurements() { Clear(ColourDesired(0, 0, 0), ColourDesired(0xff, 0xff, 0xff), 0, 0, 0, - false, false, false, false, caseMixed, true, true, false); + SC_WEIGHT_NORMAL, false, false, false, caseMixed, true, true, false); fore.desired = source.fore.desired; back.desired = source.back.desired; characterSet = source.characterSet; - bold = source.bold; + weight = source.weight; italic = source.italic; size = source.size; eolFilled = source.eolFilled; @@ -86,11 +86,11 @@ Style &Style::operator=(const Style &source) { return * this; Clear(ColourDesired(0, 0, 0), ColourDesired(0xff, 0xff, 0xff), 0, 0, SC_CHARSET_DEFAULT, - false, false, false, false, caseMixed, true, true, false); + SC_WEIGHT_NORMAL, false, false, false, caseMixed, true, true, false); fore.desired = source.fore.desired; back.desired = source.back.desired; characterSet = source.characterSet; - bold = source.bold; + weight = source.weight; italic = source.italic; size = source.size; eolFilled = source.eolFilled; @@ -103,13 +103,13 @@ Style &Style::operator=(const Style &source) { void Style::Clear(ColourDesired fore_, ColourDesired back_, int size_, const char *fontName_, int characterSet_, - bool bold_, bool italic_, bool eolFilled_, + int weight_, bool italic_, bool eolFilled_, bool underline_, ecaseForced caseForce_, bool visible_, bool changeable_, bool hotspot_) { fore.desired = fore_; back.desired = back_; characterSet = characterSet_; - bold = bold_; + weight = weight_; italic = italic_; size = size_; fontName = fontName_; @@ -130,7 +130,7 @@ void Style::ClearTo(const Style &source) { source.size, source.fontName, source.characterSet, - source.bold, + source.weight, source.italic, source.eolFilled, source.underline, diff --git a/src/Style.h b/src/Style.h index 29122b0a4..0e706d322 100644 --- a/src/Style.h +++ b/src/Style.h @@ -14,16 +14,16 @@ namespace Scintilla { struct FontSpecification { const char *fontName; - bool bold; + int weight; bool italic; int size; int characterSet; int extraFontFlag; FontSpecification() : fontName(0), - bold(false), + weight(SC_WEIGHT_NORMAL), italic(false), - size(10), + size(10 * SC_FONT_SIZE_MULTIPLIER), characterSet(0), extraFontFlag(0) { } @@ -77,7 +77,7 @@ public: void Clear(ColourDesired fore_, ColourDesired back_, int size_, const char *fontName_, int characterSet_, - bool bold_, bool italic_, bool eolFilled_, + int weight_, bool italic_, bool eolFilled_, bool underline_, ecaseForced caseForce_, bool visible_, bool changeable_, bool hotspot_); void ClearTo(const Style &source); diff --git a/src/ViewStyle.cxx b/src/ViewStyle.cxx index 9ba69b1ce..08164f648 100644 --- a/src/ViewStyle.cxx +++ b/src/ViewStyle.cxx @@ -86,14 +86,15 @@ FontRealised::~FontRealised() { frNext = 0; } -void FontRealised::Realise(Surface &surface, int zoomLevel) { +void FontRealised::Realise(Surface &surface, int zoomLevel, int technology) { PLATFORM_ASSERT(fontName); - sizeZoomed = size + zoomLevel; - if (sizeZoomed <= 2) // Hangs if sizeZoomed <= 1 - sizeZoomed = 2; + sizeZoomed = size + zoomLevel * SC_FONT_SIZE_MULTIPLIER; + if (sizeZoomed <= 2 * SC_FONT_SIZE_MULTIPLIER) // Hangs if sizeZoomed <= 1 + sizeZoomed = 2 * SC_FONT_SIZE_MULTIPLIER; - int deviceHeight = surface.DeviceHeightFont(sizeZoomed); - font.Create(fontName, characterSet, deviceHeight, bold, italic, extraFontFlag); + float deviceHeight = surface.DeviceHeightFont(sizeZoomed); + FontParameters fp(fontName, deviceHeight / SC_FONT_SIZE_MULTIPLIER, weight, italic, extraFontFlag, technology, characterSet); + font.Create(fp); ascent = surface.Ascent(font); descent = surface.Descent(font); @@ -102,7 +103,7 @@ void FontRealised::Realise(Surface &surface, int zoomLevel) { aveCharWidth = surface.AverageCharWidth(font); spaceWidth = surface.WidthChar(font, ' '); if (frNext) { - frNext->Realise(surface, zoomLevel); + frNext->Realise(surface, zoomLevel, technology); } } @@ -239,6 +240,7 @@ void ViewStyle::Init(size_t stylesSize_) { indicators[2].under = false; indicators[2].fore = ColourDesired(0xff, 0, 0); + technology = SC_TECHNOLOGY_DEFAULT; lineHeight = 1; maxAscent = 1; maxDescent = 1; @@ -388,7 +390,7 @@ void ViewStyle::Refresh(Surface &surface) { CreateFont(styles[j]); } - frFirst->Realise(surface, zoomLevel); + frFirst->Realise(surface, zoomLevel, technology); for (unsigned int k=0; k<stylesSize; k++) { FontRealised *fr = frFirst->Find(styles[k]); @@ -457,9 +459,9 @@ void ViewStyle::EnsureStyle(size_t index) { void ViewStyle::ResetDefaultStyle() { styles[STYLE_DEFAULT].Clear(ColourDesired(0,0,0), ColourDesired(0xff,0xff,0xff), - Platform::DefaultFontSize(), fontNames.Save(Platform::DefaultFont()), + Platform::DefaultFontSize() * SC_FONT_SIZE_MULTIPLIER, fontNames.Save(Platform::DefaultFont()), SC_CHARSET_DEFAULT, - false, false, false, false, Style::caseMixed, true, true, false); + SC_WEIGHT_NORMAL, false, false, false, Style::caseMixed, true, true, false); } void ViewStyle::ClearStyles() { diff --git a/src/ViewStyle.h b/src/ViewStyle.h index b038a9b54..b15b9163c 100644 --- a/src/ViewStyle.h +++ b/src/ViewStyle.h @@ -48,7 +48,7 @@ public: FontRealised *frNext; FontRealised(const FontSpecification &fs); virtual ~FontRealised(); - void Realise(Surface &surface, int zoomLevel); + void Realise(Surface &surface, int zoomLevel, int technology); FontRealised *Find(const FontSpecification &fs); void FindMaxAscentDescent(unsigned int &maxAscent, unsigned int &maxDescent); }; @@ -67,6 +67,7 @@ public: Style *styles; LineMarker markers[MARKER_MAX + 1]; Indicator indicators[INDIC_MAX + 1]; + int technology; int lineHeight; unsigned int maxAscent; unsigned int maxDescent; diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index 0ccc8aa13..00e0bf576 100644 --- a/win32/PlatWin.cxx +++ b/win32/PlatWin.cxx @@ -26,6 +26,8 @@ #include <commctrl.h> #include <richedit.h> #include <windowsx.h> +#include <d2d1.h> +#include <dwrite.h> #include "Platform.h" #include "UniConversion.h" @@ -195,6 +197,88 @@ void Palette::Allocate(Window &) { } } +IDWriteFactory *pIDWriteFactory = 0; +ID2D1Factory *pD2DFactory = 0; + +bool LoadD2D() { + static bool triedLoadingD2D = false; + static HMODULE hDLLD2D = 0; + static HMODULE hDLLDWrite = 0; + if (!triedLoadingD2D) { + typedef HRESULT (WINAPI *D2D1CFSig)(D2D1_FACTORY_TYPE factoryType, REFIID riid, + CONST D2D1_FACTORY_OPTIONS *pFactoryOptions, IUnknown **factory); + typedef HRESULT (WINAPI *DWriteCFSig)(DWRITE_FACTORY_TYPE factoryType, REFIID iid, + IUnknown **factory); + + hDLLD2D = ::LoadLibrary(TEXT("D2D1.DLL")); + if (hDLLD2D) { + D2D1CFSig fnD2DCF = (D2D1CFSig)::GetProcAddress(hDLLD2D, "D2D1CreateFactory"); + if (fnD2DCF) { + // A single threaded factory as Scintilla always draw on the GUI thread + fnD2DCF(D2D1_FACTORY_TYPE_SINGLE_THREADED, + __uuidof(ID2D1Factory), + 0, + reinterpret_cast<IUnknown**>(&pD2DFactory)); + } + } + hDLLDWrite = ::LoadLibrary(TEXT("DWRITE.DLL")); + if (hDLLDWrite) { + DWriteCFSig fnDWCF = (DWriteCFSig)::GetProcAddress(hDLLDWrite, "DWriteCreateFactory"); + if (fnDWCF) { + fnDWCF(DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory), + reinterpret_cast<IUnknown**>(&pIDWriteFactory)); + } + } + } + triedLoadingD2D = true; + return pIDWriteFactory && pD2DFactory; +} + +struct FormatAndMetrics { + int technology; + HFONT hfont; + IDWriteTextFormat *pTextFormat; + int extraFontFlag; + FLOAT yAscent; + FLOAT yDescent; + FormatAndMetrics(HFONT hfont_, int extraFontFlag_) : + technology(SCWIN_TECH_GDI), hfont(hfont_), pTextFormat(0), extraFontFlag(extraFontFlag_), yAscent(2), yDescent(1) { + } + FormatAndMetrics(IDWriteTextFormat *pTextFormat_, int extraFontFlag_, FLOAT yAscent_, FLOAT yDescent_) : + technology(SCWIN_TECH_DIRECTWRITE), hfont(0), pTextFormat(pTextFormat_), extraFontFlag(extraFontFlag_), yAscent(yAscent_), yDescent(yDescent_) { + } + ~FormatAndMetrics() { + if (hfont) + ::DeleteObject(hfont); + if (pTextFormat) + pTextFormat->Release(); + pTextFormat = 0; + extraFontFlag = 0; + yAscent = 2; + yDescent = 1; + } + HFONT HFont(); +}; + +HFONT FormatAndMetrics::HFont() { + if (technology == SCWIN_TECH_GDI) { + return hfont; + } else { + LOGFONTW lf; + memset(&lf, 0, sizeof(lf)); + + HRESULT hr = pTextFormat->GetFontFamilyName(lf.lfFaceName, LF_FACESIZE); + if (SUCCEEDED(hr)) { + lf.lfWeight = pTextFormat->GetFontWeight(); + lf.lfItalic = pTextFormat->GetFontStyle() == DWRITE_FONT_STYLE_ITALIC; + lf.lfHeight = -static_cast<int>(pTextFormat->GetFontSize()); + return ::CreateFontIndirectW(&lf); + } + } + return 0; +} + #ifndef CLEARTYPE_QUALITY #define CLEARTYPE_QUALITY 5 #endif @@ -216,11 +300,28 @@ static BYTE Win32MapFontQuality(int extraFontFlag) { } } -static void SetLogFont(LOGFONTA &lf, const char *faceName, int characterSet, int size, bool bold, bool italic, int extraFontFlag) { +static D2D1_TEXT_ANTIALIAS_MODE DWriteMapFontQuality(int extraFontFlag) { + switch (extraFontFlag & SC_EFF_QUALITY_MASK) { + + case SC_EFF_QUALITY_NON_ANTIALIASED: + return D2D1_TEXT_ANTIALIAS_MODE_ALIASED; + + case SC_EFF_QUALITY_ANTIALIASED: + return D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; + + case SC_EFF_QUALITY_LCD_OPTIMIZED: + return D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; + + default: + return D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; + } +} + +static void SetLogFont(LOGFONTA &lf, const char *faceName, int characterSet, float size, int weight, bool italic, int extraFontFlag) { memset(&lf, 0, sizeof(lf)); // The negative is to allow for leading - lf.lfHeight = -(abs(size)); - lf.lfWeight = bold ? FW_BOLD : FW_NORMAL; + lf.lfHeight = -(abs(static_cast<int>(size + 0.5))); + lf.lfWeight = weight; lf.lfItalic = static_cast<BYTE>(italic ? 1 : 0); lf.lfCharSet = static_cast<BYTE>(characterSet); lf.lfQuality = Win32MapFontQuality(extraFontFlag); @@ -232,71 +333,111 @@ static void SetLogFont(LOGFONTA &lf, const char *faceName, int characterSet, int * If one font is the same as another, its hash will be the same, but if the hash is the * same then they may still be different. */ -static int HashFont(const char *faceName, int characterSet, int size, bool bold, bool italic, int extraFontFlag) { +static int HashFont(const FontParameters &fp) { return - size ^ - (characterSet << 10) ^ - ((extraFontFlag & SC_EFF_QUALITY_MASK) << 9) ^ - (bold ? 0x10000000 : 0) ^ - (italic ? 0x20000000 : 0) ^ - faceName[0]; + static_cast<int>(fp.size) ^ + (fp.characterSet << 10) ^ + ((fp.extraFontFlag & SC_EFF_QUALITY_MASK) << 9) ^ + ((fp.weight/100) << 12) ^ + (fp.italic ? 0x20000000 : 0) ^ + (fp.technology << 15) ^ + fp.faceName[0]; } class FontCached : Font { FontCached *next; int usage; + float size; LOGFONTA lf; + int technology; int hash; - FontCached(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_, int extraFontFlag_); + FontCached(const FontParameters &fp); ~FontCached() {} - bool SameAs(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_, int extraFontFlag_); + bool SameAs(const FontParameters &fp); virtual void Release(); static FontCached *first; public: - static FontID FindOrCreate(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_, int extraFontFlag_); + static FontID FindOrCreate(const FontParameters &fp); static void ReleaseId(FontID fid_); }; FontCached *FontCached::first = 0; -FontCached::FontCached(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_, int extraFontFlag_) : - next(0), usage(0), hash(0) { - SetLogFont(lf, faceName_, characterSet_, size_, bold_, italic_, extraFontFlag_); - hash = HashFont(faceName_, characterSet_, size_, bold_, italic_, extraFontFlag_); - fid = ::CreateFontIndirectA(&lf); +FontCached::FontCached(const FontParameters &fp) : + next(0), usage(0), size(1.0), hash(0) { + SetLogFont(lf, fp.faceName, fp.characterSet, fp.size, fp.weight, fp.italic, fp.extraFontFlag); + technology = fp.technology; + hash = HashFont(fp); + fid = 0; + if (technology == SCWIN_TECH_GDI) { + HFONT hfont = ::CreateFontIndirectA(&lf); + fid = reinterpret_cast<void *>(new FormatAndMetrics(hfont, fp.extraFontFlag)); + } else { + IDWriteTextFormat *pTextFormat; + const int faceSize = 200; + WCHAR wszFace[faceSize]; + UTF16FromUTF8(fp.faceName, strlen(fp.faceName)+1, wszFace, faceSize); + FLOAT fHeight = fp.size; + DWRITE_FONT_STYLE style = fp.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL; + HRESULT hr = pIDWriteFactory->CreateTextFormat(wszFace, NULL, + static_cast<DWRITE_FONT_WEIGHT>(fp.weight), + style, + DWRITE_FONT_STRETCH_NORMAL, fHeight, L"en-us", &pTextFormat); + if (SUCCEEDED(hr)) { + pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP); + + const int maxLines = 2; + DWRITE_LINE_METRICS lineMetrics[maxLines]; + UINT32 lineCount = 0; + FLOAT yAscent = 1.0f; + FLOAT yDescent = 1.0f; + IDWriteTextLayout *pTextLayout = 0; + hr = pIDWriteFactory->CreateTextLayout(L"X", 1, pTextFormat, + 100.0f, 100.0f, &pTextLayout); + if (SUCCEEDED(hr)) { + hr = pTextLayout->GetLineMetrics(lineMetrics, maxLines, &lineCount); + if (SUCCEEDED(hr)) { + yAscent = lineMetrics[0].baseline; + yDescent = lineMetrics[0].height - lineMetrics[0].baseline; + } + pTextLayout->Release(); + } + fid = reinterpret_cast<void *>(new FormatAndMetrics(pTextFormat, fp.extraFontFlag, yAscent, yDescent)); + } + } usage = 1; } -bool FontCached::SameAs(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_, int extraFontFlag_) { +bool FontCached::SameAs(const FontParameters &fp) { return - (lf.lfHeight == -(abs(size_))) && - (lf.lfWeight == (bold_ ? FW_BOLD : FW_NORMAL)) && - (lf.lfItalic == static_cast<BYTE>(italic_ ? 1 : 0)) && - (lf.lfCharSet == characterSet_) && - (lf.lfQuality == Win32MapFontQuality(extraFontFlag_)) && - 0 == strcmp(lf.lfFaceName,faceName_); + (size == fp.size) && + (lf.lfWeight == fp.weight) && + (lf.lfItalic == static_cast<BYTE>(fp.italic ? 1 : 0)) && + (lf.lfCharSet == fp.characterSet) && + (lf.lfQuality == Win32MapFontQuality(fp.extraFontFlag)) && + (technology == fp.technology) && + 0 == strcmp(lf.lfFaceName,fp.faceName); } void FontCached::Release() { - if (fid) - ::DeleteObject(fid); + delete reinterpret_cast<FormatAndMetrics *>(fid); fid = 0; } -FontID FontCached::FindOrCreate(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_, int extraFontFlag_) { +FontID FontCached::FindOrCreate(const FontParameters &fp) { FontID ret = 0; ::EnterCriticalSection(&crPlatformLock); - int hashFind = HashFont(faceName_, characterSet_, size_, bold_, italic_, extraFontFlag_); + int hashFind = HashFont(fp); for (FontCached *cur=first; cur; cur=cur->next) { if ((cur->hash == hashFind) && - cur->SameAs(faceName_, characterSet_, size_, bold_, italic_, extraFontFlag_)) { + cur->SameAs(fp)) { cur->usage++; ret = cur->fid; } } if (ret == 0) { - FontCached *fc = new FontCached(faceName_, characterSet_, size_, bold_, italic_, extraFontFlag_); + FontCached *fc = new FontCached(fp); if (fc) { fc->next = first; first = fc; @@ -335,35 +476,62 @@ Font::~Font() { #define FONTS_CACHED -void Font::Create(const char *faceName, int characterSet, int size, - bool bold, bool italic, int extraFontFlag) { +void Font::Create(const FontParameters &fp) { Release(); -#ifndef FONTS_CACHED - LOGFONT lf; - SetLogFont(lf, faceName, characterSet, size, bold, italic, extraFontFlag); - fid = ::CreateFontIndirect(&lf); -#else - if (faceName) - fid = FontCached::FindOrCreate(faceName, characterSet, size, bold, italic, extraFontFlag); -#endif + if (fp.faceName) + fid = FontCached::FindOrCreate(fp); } void Font::Release() { -#ifndef FONTS_CACHED - if (fid) - ::DeleteObject(fid); -#else if (fid) FontCached::ReleaseId(fid); -#endif fid = 0; } +// Buffer to hold strings and string position arrays without always allocating on heap. +// May sometimes have string too long to allocate on stack. So use a fixed stack-allocated buffer +// when less than safe size otherwise allocate on heap and free automatically. +template<typename T, int lengthStandard> +class VarBuffer { + T bufferStandard[lengthStandard]; +public: + T *buffer; + VarBuffer(size_t length) : buffer(0) { + if (length > lengthStandard) { + buffer = new T[length]; + } else { + buffer = bufferStandard; + } + } + ~VarBuffer() { + if (buffer != bufferStandard) { + delete []buffer; + buffer = 0; + } + } +}; + +const int stackBufferLength = 10000; +class TextWide : public VarBuffer<wchar_t, stackBufferLength> { +public: + int tlen; + TextWide(const char *s, int len, bool unicodeMode, int codePage=0) : + VarBuffer<wchar_t, stackBufferLength>(len) { + if (unicodeMode) { + tlen = UTF16FromUTF8(s, len, buffer, len); + } else { + // Support Asian string display in 9x English + tlen = ::MultiByteToWideChar(codePage, 0, s, len, buffer, len); + } + } +}; +typedef VarBuffer<XYPOSITION, stackBufferLength> TextPositions; + #ifdef SCI_NAMESPACE namespace Scintilla { #endif -class SurfaceImpl : public Surface { +class SurfaceGDI : public Surface { bool unicodeMode; HDC hdc; bool hdcOwned; @@ -386,12 +554,12 @@ class SurfaceImpl : public Surface { void BrushColor(ColourAllocated back); void SetFont(Font &font_); - // Private so SurfaceImpl objects can not be copied - SurfaceImpl(const SurfaceImpl &); - SurfaceImpl &operator=(const SurfaceImpl &); + // Private so SurfaceGDI objects can not be copied + SurfaceGDI(const SurfaceGDI &); + SurfaceGDI &operator=(const SurfaceGDI &); public: - SurfaceImpl(); - virtual ~SurfaceImpl(); + SurfaceGDI(); + virtual ~SurfaceGDI(); void Init(WindowID wid); void Init(SurfaceID sid, WindowID wid); @@ -415,19 +583,19 @@ public: void Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back); void Copy(PRectangle rc, Point from, Surface &surfaceSource); - void DrawTextCommon(PRectangle rc, Font &font_, int ybase, const char *s, int len, UINT fuOptions); - void DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back); - void DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back); - void DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore); - void MeasureWidths(Font &font_, const char *s, int len, int *positions); - int WidthText(Font &font_, const char *s, int len); - int WidthChar(Font &font_, char ch); - int Ascent(Font &font_); - int Descent(Font &font_); - int InternalLeading(Font &font_); - int ExternalLeading(Font &font_); - int Height(Font &font_); - int AverageCharWidth(Font &font_); + void DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, UINT fuOptions); + void DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back); + void DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back); + void DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore); + void MeasureWidths(Font &font_, const char *s, int len, XYPOSITION *positions); + XYPOSITION WidthText(Font &font_, const char *s, int len); + XYPOSITION WidthChar(Font &font_, char ch); + XYPOSITION Ascent(Font &font_); + XYPOSITION Descent(Font &font_); + XYPOSITION InternalLeading(Font &font_); + XYPOSITION ExternalLeading(Font &font_); + XYPOSITION Height(Font &font_); + XYPOSITION AverageCharWidth(Font &font_); int SetPalette(Palette *pal, bool inBackGround); void SetClip(PRectangle rc); @@ -441,7 +609,7 @@ public: } //namespace Scintilla #endif -SurfaceImpl::SurfaceImpl() : +SurfaceGDI::SurfaceGDI() : unicodeMode(false), hdc(0), hdcOwned(false), pen(0), penOld(0), @@ -459,11 +627,11 @@ SurfaceImpl::SurfaceImpl() : win9xACPSame = false; } -SurfaceImpl::~SurfaceImpl() { +SurfaceGDI::~SurfaceGDI() { Release(); } -void SurfaceImpl::Release() { +void SurfaceGDI::Release() { if (penOld) { ::SelectObject(reinterpret_cast<HDC>(hdc), penOld); ::DeleteObject(pen); @@ -501,33 +669,33 @@ void SurfaceImpl::Release() { } } -bool SurfaceImpl::Initialised() { +bool SurfaceGDI::Initialised() { return hdc != 0; } -void SurfaceImpl::Init(WindowID) { +void SurfaceGDI::Init(WindowID) { Release(); hdc = ::CreateCompatibleDC(NULL); hdcOwned = true; ::SetTextAlign(reinterpret_cast<HDC>(hdc), TA_BASELINE); } -void SurfaceImpl::Init(SurfaceID sid, WindowID) { +void SurfaceGDI::Init(SurfaceID sid, WindowID) { Release(); hdc = reinterpret_cast<HDC>(sid); ::SetTextAlign(reinterpret_cast<HDC>(hdc), TA_BASELINE); } -void SurfaceImpl::InitPixMap(int width, int height, Surface *surface_, WindowID) { +void SurfaceGDI::InitPixMap(int width, int height, Surface *surface_, WindowID) { Release(); - hdc = ::CreateCompatibleDC(static_cast<SurfaceImpl *>(surface_)->hdc); + hdc = ::CreateCompatibleDC(static_cast<SurfaceGDI *>(surface_)->hdc); hdcOwned = true; - bitmap = ::CreateCompatibleBitmap(static_cast<SurfaceImpl *>(surface_)->hdc, width, height); + bitmap = ::CreateCompatibleBitmap(static_cast<SurfaceGDI *>(surface_)->hdc, width, height); bitmapOld = static_cast<HBITMAP>(::SelectObject(hdc, bitmap)); ::SetTextAlign(reinterpret_cast<HDC>(hdc), TA_BASELINE); } -void SurfaceImpl::PenColour(ColourAllocated fore) { +void SurfaceGDI::PenColour(ColourAllocated fore) { if (pen) { ::SelectObject(hdc, penOld); ::DeleteObject(pen); @@ -538,7 +706,7 @@ void SurfaceImpl::PenColour(ColourAllocated fore) { penOld = static_cast<HPEN>(::SelectObject(reinterpret_cast<HDC>(hdc), pen)); } -void SurfaceImpl::BrushColor(ColourAllocated back) { +void SurfaceGDI::BrushColor(ColourAllocated back) { if (brush) { ::SelectObject(hdc, brushOld); ::DeleteObject(brush); @@ -551,46 +719,48 @@ void SurfaceImpl::BrushColor(ColourAllocated back) { brushOld = static_cast<HBRUSH>(::SelectObject(hdc, brush)); } -void SurfaceImpl::SetFont(Font &font_) { +void SurfaceGDI::SetFont(Font &font_) { if (font_.GetID() != font) { + FormatAndMetrics *pfm = reinterpret_cast<FormatAndMetrics *>(font_.GetID()); + PLATFORM_ASSERT(pfm->technology == SCWIN_TECH_GDI); if (fontOld) { - ::SelectObject(hdc, font_.GetID()); + ::SelectObject(hdc, pfm->hfont); } else { - fontOld = static_cast<HFONT>(::SelectObject(hdc, font_.GetID())); + fontOld = static_cast<HFONT>(::SelectObject(hdc, pfm->hfont)); } - font = reinterpret_cast<HFONT>(font_.GetID()); + font = reinterpret_cast<HFONT>(pfm->hfont); } } -int SurfaceImpl::LogPixelsY() { +int SurfaceGDI::LogPixelsY() { return ::GetDeviceCaps(hdc, LOGPIXELSY); } -int SurfaceImpl::DeviceHeightFont(int points) { +int SurfaceGDI::DeviceHeightFont(int points) { return ::MulDiv(points, LogPixelsY(), 72); } -void SurfaceImpl::MoveTo(int x_, int y_) { +void SurfaceGDI::MoveTo(int x_, int y_) { ::MoveToEx(hdc, x_, y_, 0); } -void SurfaceImpl::LineTo(int x_, int y_) { +void SurfaceGDI::LineTo(int x_, int y_) { ::LineTo(hdc, x_, y_); } -void SurfaceImpl::Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back) { +void SurfaceGDI::Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back) { PenColour(fore); BrushColor(back); ::Polygon(hdc, reinterpret_cast<POINT *>(pts), npts); } -void SurfaceImpl::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) { +void SurfaceGDI::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) { PenColour(fore); BrushColor(back); ::Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom); } -void SurfaceImpl::FillRectangle(PRectangle rc, ColourAllocated back) { +void SurfaceGDI::FillRectangle(PRectangle rc, ColourAllocated back) { // Using ExtTextOut rather than a FillRect ensures that no dithering occurs. // There is no need to allocate a brush either. RECT rcw = RectFromPRectangle(rc); @@ -598,10 +768,10 @@ void SurfaceImpl::FillRectangle(PRectangle rc, ColourAllocated back) { ::ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE, &rcw, TEXT(""), 0, NULL); } -void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) { +void SurfaceGDI::FillRectangle(PRectangle rc, Surface &surfacePattern) { HBRUSH br; - if (static_cast<SurfaceImpl &>(surfacePattern).bitmap) - br = ::CreatePatternBrush(static_cast<SurfaceImpl &>(surfacePattern).bitmap); + if (static_cast<SurfaceGDI &>(surfacePattern).bitmap) + br = ::CreatePatternBrush(static_cast<SurfaceGDI &>(surfacePattern).bitmap); else // Something is wrong so display in red br = ::CreateSolidBrush(RGB(0xff, 0, 0)); RECT rcw = RectFromPRectangle(rc); @@ -609,7 +779,7 @@ void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) { ::DeleteObject(br); } -void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back) { +void SurfaceGDI::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back) { PenColour(fore); BrushColor(back); ::RoundRect(hdc, @@ -645,7 +815,7 @@ static DWORD dwordFromBGRA(byte b, byte g, byte r, byte a) { return converter.val; } -void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill, +void SurfaceGDI::AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill, ColourAllocated outline, int alphaOutline, int /* flags*/ ) { if (AlphaBlendFn && rc.Width() > 0) { HDC hMemDC = ::CreateCompatibleDC(reinterpret_cast<HDC>(hdc)); @@ -704,7 +874,7 @@ void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated } } -void SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) { +void SurfaceGDI::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) { if (AlphaBlendFn && rc.Width() > 0) { HDC hMemDC = ::CreateCompatibleDC(reinterpret_cast<HDC>(hdc)); if (rc.Width() > width) @@ -743,58 +913,21 @@ void SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height, const unsi } } -void SurfaceImpl::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) { +void SurfaceGDI::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) { PenColour(fore); BrushColor(back); ::Ellipse(hdc, rc.left, rc.top, rc.right, rc.bottom); } -void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) { +void SurfaceGDI::Copy(PRectangle rc, Point from, Surface &surfaceSource) { ::BitBlt(hdc, rc.left, rc.top, rc.Width(), rc.Height(), - static_cast<SurfaceImpl &>(surfaceSource).hdc, from.x, from.y, SRCCOPY); + static_cast<SurfaceGDI &>(surfaceSource).hdc, from.x, from.y, SRCCOPY); } -// Buffer to hold strings and string position arrays without always allocating on heap. -// May sometimes have string too long to allocate on stack. So use a fixed stack-allocated buffer -// when less than safe size otherwise allocate on heap and free automatically. -template<typename T, int lengthStandard> -class VarBuffer { - T bufferStandard[lengthStandard]; -public: - T *buffer; - VarBuffer(size_t length) : buffer(0) { - if (length > lengthStandard) { - buffer = new T[length]; - } else { - buffer = bufferStandard; - } - } - ~VarBuffer() { - if (buffer != bufferStandard) { - delete []buffer; - buffer = 0; - } - } -}; +typedef VarBuffer<int, stackBufferLength> TextPositionsI; -const int stackBufferLength = 10000; -class TextWide : public VarBuffer<wchar_t, stackBufferLength> { -public: - int tlen; - TextWide(const char *s, int len, bool unicodeMode, int codePage=0) : - VarBuffer<wchar_t, stackBufferLength>(len) { - if (unicodeMode) { - tlen = UTF16FromUTF8(s, len, buffer, len); - } else { - // Support Asian string display in 9x English - tlen = ::MultiByteToWideChar(codePage, 0, s, len, buffer, len); - } - } -}; -typedef VarBuffer<int, stackBufferLength> TextPositions; - -void SurfaceImpl::DrawTextCommon(PRectangle rc, Font &font_, int ybase, const char *s, int len, UINT fuOptions) { +void SurfaceGDI::DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, UINT fuOptions) { SetFont(font_); RECT rcw = RectFromPRectangle(rc); SIZE sz={0,0}; @@ -838,21 +971,21 @@ void SurfaceImpl::DrawTextCommon(PRectangle rc, Font &font_, int ybase, const ch } } -void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len, +void SurfaceGDI::DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back) { ::SetTextColor(hdc, fore.AsLong()); ::SetBkColor(hdc, back.AsLong()); DrawTextCommon(rc, font_, ybase, s, len, ETO_OPAQUE); } -void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, +void SurfaceGDI::DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back) { ::SetTextColor(hdc, fore.AsLong()); ::SetBkColor(hdc, back.AsLong()); DrawTextCommon(rc, font_, ybase, s, len, ETO_OPAQUE | ETO_CLIPPED); } -void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, +void SurfaceGDI::DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore) { // Avoid drawing spaces in transparent mode for (int i=0;i<len;i++) { @@ -866,7 +999,7 @@ void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, int ybase, con } } -int SurfaceImpl::WidthText(Font &font_, const char *s, int len) { +XYPOSITION SurfaceGDI::WidthText(Font &font_, const char *s, int len) { SetFont(font_); SIZE sz={0,0}; if ((!unicodeMode) && (IsNT() || (codePage==0) || win9xACPSame)) { @@ -878,13 +1011,13 @@ int SurfaceImpl::WidthText(Font &font_, const char *s, int len) { return sz.cx; } -void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positions) { +void SurfaceGDI::MeasureWidths(Font &font_, const char *s, int len, XYPOSITION *positions) { SetFont(font_); SIZE sz={0,0}; int fit = 0; if (unicodeMode) { const TextWide tbuf(s, len, unicodeMode, codePage); - TextPositions poses(tbuf.tlen); + TextPositionsI poses(tbuf.tlen); fit = tbuf.tlen; if (!::GetTextExtentExPointW(hdc, tbuf.buffer, tbuf.tlen, maxWidthMeasure, &fit, poses.buffer, &sz)) { // Likely to have failed because on Windows 9x where function not available @@ -928,19 +1061,19 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positi int startOffset = 0; while (len > 0) { int lenBlock = Platform::Minimum(len, maxLenText); - if (!::GetTextExtentExPointA(hdc, s, lenBlock, maxWidthMeasure, &fit, positions, &sz)) { + TextPositionsI poses(len); + if (!::GetTextExtentExPointA(hdc, s, lenBlock, maxWidthMeasure, &fit, poses.buffer, &sz)) { // Eeek - a NULL DC or other foolishness could cause this. return; } else if (fit < lenBlock) { // For some reason, such as an incomplete DBCS character // Not all the positions are filled in so make them equal to end. - for (int i=fit;i<lenBlock;i++) - positions[i] = positions[fit-1]; - } else if (startOffset > 0) { - for (int i=0;i<lenBlock;i++) - positions[i] += startOffset; + for (int i = fit;i<lenBlock;i++) + poses.buffer[i] = poses.buffer[fit-1]; } - startOffset = positions[lenBlock-1]; + for (int i=0;i<lenBlock;i++) + positions[i] = poses.buffer[i] + startOffset; + startOffset = poses.buffer[lenBlock-1]; len -= lenBlock; positions += lenBlock; s += lenBlock; @@ -948,7 +1081,7 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positi } else { // Support Asian string display in 9x English const TextWide tbuf(s, len, unicodeMode, codePage); - TextPositions poses(tbuf.tlen); + TextPositionsI poses(tbuf.tlen); for (int widthSS=0; widthSS<tbuf.tlen; widthSS++) { ::GetTextExtentPoint32W(hdc, tbuf.buffer, widthSS+1, &sz); poses.buffer[widthSS] = sz.cx; @@ -970,56 +1103,56 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positi } } -int SurfaceImpl::WidthChar(Font &font_, char ch) { +XYPOSITION SurfaceGDI::WidthChar(Font &font_, char ch) { SetFont(font_); SIZE sz; ::GetTextExtentPoint32A(hdc, &ch, 1, &sz); return sz.cx; } -int SurfaceImpl::Ascent(Font &font_) { +XYPOSITION SurfaceGDI::Ascent(Font &font_) { SetFont(font_); TEXTMETRIC tm; ::GetTextMetrics(hdc, &tm); return tm.tmAscent; } -int SurfaceImpl::Descent(Font &font_) { +XYPOSITION SurfaceGDI::Descent(Font &font_) { SetFont(font_); TEXTMETRIC tm; ::GetTextMetrics(hdc, &tm); return tm.tmDescent; } -int SurfaceImpl::InternalLeading(Font &font_) { +XYPOSITION SurfaceGDI::InternalLeading(Font &font_) { SetFont(font_); TEXTMETRIC tm; ::GetTextMetrics(hdc, &tm); return tm.tmInternalLeading; } -int SurfaceImpl::ExternalLeading(Font &font_) { +XYPOSITION SurfaceGDI::ExternalLeading(Font &font_) { SetFont(font_); TEXTMETRIC tm; ::GetTextMetrics(hdc, &tm); return tm.tmExternalLeading; } -int SurfaceImpl::Height(Font &font_) { +XYPOSITION SurfaceGDI::Height(Font &font_) { SetFont(font_); TEXTMETRIC tm; ::GetTextMetrics(hdc, &tm); return tm.tmHeight; } -int SurfaceImpl::AverageCharWidth(Font &font_) { +XYPOSITION SurfaceGDI::AverageCharWidth(Font &font_) { SetFont(font_); TEXTMETRIC tm; ::GetTextMetrics(hdc, &tm); return tm.tmAveCharWidth; } -int SurfaceImpl::SetPalette(Palette *pal, bool inBackGround) { +int SurfaceGDI::SetPalette(Palette *pal, bool inBackGround) { if (paletteOld) { ::SelectPalette(hdc, paletteOld, TRUE); } @@ -1033,28 +1166,705 @@ int SurfaceImpl::SetPalette(Palette *pal, bool inBackGround) { return changes; } -void SurfaceImpl::SetClip(PRectangle rc) { +void SurfaceGDI::SetClip(PRectangle rc) { ::IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom); } -void SurfaceImpl::FlushCachedState() { +void SurfaceGDI::FlushCachedState() { pen = 0; brush = 0; font = 0; } -void SurfaceImpl::SetUnicodeMode(bool unicodeMode_) { +void SurfaceGDI::SetUnicodeMode(bool unicodeMode_) { unicodeMode=unicodeMode_; } -void SurfaceImpl::SetDBCSMode(int codePage_) { +void SurfaceGDI::SetDBCSMode(int codePage_) { // No action on window as automatically handled by system. codePage = codePage_; win9xACPSame = !IsNT() && ((unsigned int)codePage == ::GetACP()); } -Surface *Surface::Allocate() { - return new SurfaceImpl; +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +class SurfaceD2D : public Surface { + bool unicodeMode; + int x, y; + + int codePage; + + ID2D1RenderTarget *pRenderTarget; + bool ownRenderTarget; + int clipsActive; + + IDWriteTextFormat *pTextFormat; + FLOAT yAscent; + FLOAT yDescent; + + ID2D1SolidColorBrush *pBrush; + + int logPixelsY; + float dpiScaleX; + float dpiScaleY; + + void SetFont(Font &font_); + + // Private so SurfaceD2D objects can not be copied + SurfaceD2D(const SurfaceD2D &); + SurfaceD2D &operator=(const SurfaceD2D &); +public: + SurfaceD2D(); + virtual ~SurfaceD2D(); + + void SetScale(); + void Init(WindowID wid); + void Init(SurfaceID sid, WindowID wid); + void InitPixMap(int width, int height, Surface *surface_, WindowID wid); + + void Release(); + bool Initialised(); + + HRESULT FlushDrawing(); + + void PenColour(ColourAllocated fore); + void D2DPenColour(ColourAllocated fore, int alpha=255); + int LogPixelsY(); + int DeviceHeightFont(int points); + void MoveTo(int x_, int y_); + void LineTo(int x_, int y_); + void Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back); + void RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back); + void FillRectangle(PRectangle rc, ColourAllocated back); + void FillRectangle(PRectangle rc, Surface &surfacePattern); + void RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back); + void AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill, + ColourAllocated outline, int alphaOutline, int flags); + void DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage); + void Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back); + void Copy(PRectangle rc, Point from, Surface &surfaceSource); + + void DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, UINT fuOptions); + void DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back); + void DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back); + void DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, ColourAllocated fore); + void MeasureWidths(Font &font_, const char *s, int len, XYPOSITION *positions); + XYPOSITION WidthText(Font &font_, const char *s, int len); + XYPOSITION WidthChar(Font &font_, char ch); + XYPOSITION Ascent(Font &font_); + XYPOSITION Descent(Font &font_); + XYPOSITION InternalLeading(Font &font_); + XYPOSITION ExternalLeading(Font &font_); + XYPOSITION Height(Font &font_); + XYPOSITION AverageCharWidth(Font &font_); + + int SetPalette(Palette *pal, bool inBackGround); + void SetClip(PRectangle rc); + void FlushCachedState(); + + void SetUnicodeMode(bool unicodeMode_); + void SetDBCSMode(int codePage_); +}; + +#ifdef SCI_NAMESPACE +} //namespace Scintilla +#endif + +SurfaceD2D::SurfaceD2D() : + unicodeMode(false), + x(0), y(0) { + + codePage = 0; + + pRenderTarget = NULL; + ownRenderTarget = false; + clipsActive = 0; + + // From selected font + pTextFormat = NULL; + yAscent = 2; + yDescent = 1; + + pBrush = NULL; + + logPixelsY = 72; + dpiScaleX = 1.0; + dpiScaleY = 1.0; +} + +SurfaceD2D::~SurfaceD2D() { + Release(); +} + +void SurfaceD2D::Release() { + if (pBrush) { + pBrush->Release(); + pBrush = 0; + } + if (pRenderTarget) { + while (clipsActive) { + pRenderTarget->PopAxisAlignedClip(); + clipsActive--; + } + if (ownRenderTarget) { + pRenderTarget->Release(); + } + pRenderTarget = 0; + } +} + +void SurfaceD2D::SetScale() { + HDC hdcMeasure = ::CreateCompatibleDC(NULL); + logPixelsY = ::GetDeviceCaps(hdcMeasure, LOGPIXELSY); + dpiScaleX = ::GetDeviceCaps(hdcMeasure, LOGPIXELSX) / 96.0f; + dpiScaleY = logPixelsY / 96.0f; + ::DeleteDC(hdcMeasure); +} + +bool SurfaceD2D::Initialised() { + return pRenderTarget != 0; +} + +HRESULT SurfaceD2D::FlushDrawing() { + return pRenderTarget->Flush(); +} + +void SurfaceD2D::Init(WindowID /* wid */) { + Release(); + SetScale(); +} + +void SurfaceD2D::Init(SurfaceID sid, WindowID) { + Release(); + SetScale(); + pRenderTarget = reinterpret_cast<ID2D1HwndRenderTarget *>(sid); +} + +void SurfaceD2D::InitPixMap(int width, int height, Surface *surface_, WindowID) { + Release(); + SetScale(); + SurfaceD2D *psurfOther = static_cast<SurfaceD2D *>(surface_); + ID2D1BitmapRenderTarget *pCompatibleRenderTarget = NULL; + HRESULT hr = psurfOther->pRenderTarget->CreateCompatibleRenderTarget( + D2D1::SizeF(width, height), &pCompatibleRenderTarget); + if (SUCCEEDED(hr)) { + pRenderTarget = pCompatibleRenderTarget; + pRenderTarget->BeginDraw(); + ownRenderTarget = true; + } +} + +void SurfaceD2D::PenColour(ColourAllocated fore) { + D2DPenColour(fore); +} + +void SurfaceD2D::D2DPenColour(ColourAllocated fore, int alpha) { + if (pRenderTarget) { + D2D_COLOR_F col; + col.r = (fore.AsLong() & 0xff) / 255.0; + col.g = ((fore.AsLong() & 0xff00) >> 8) / 255.0; + col.b = (fore.AsLong() >> 16) / 255.0; + col.a = alpha / 255.0; + if (pBrush) { + pBrush->SetColor(col); + } else { + HRESULT hr = pRenderTarget->CreateSolidColorBrush(col, &pBrush); + if (!SUCCEEDED(hr) && pBrush) { + pBrush->Release(); + pBrush = 0; + } + } + } +} + +void SurfaceD2D::SetFont(Font &font_) { + FormatAndMetrics *pfm = reinterpret_cast<FormatAndMetrics *>(font_.GetID()); + PLATFORM_ASSERT(pfm->technology == SCWIN_TECH_DIRECTWRITE); + pTextFormat = pfm->pTextFormat; + yAscent = pfm->yAscent; + yDescent = pfm->yDescent; + if (pRenderTarget) { + pRenderTarget->SetTextAntialiasMode(DWriteMapFontQuality(pfm->extraFontFlag)); + } +} + +int SurfaceD2D::LogPixelsY() { + return logPixelsY; +} + +int SurfaceD2D::DeviceHeightFont(int points) { + return ::MulDiv(points, LogPixelsY(), 72); +} + +void SurfaceD2D::MoveTo(int x_, int y_) { + x = x_; + y = y_; +} + +static int Delta(int difference) { + if (difference < 0) + return -1; + else if (difference > 0) + return 1; + else + return 0; +} + +static int RoundFloat(float f) { + return int(f+0.5); +} + +void SurfaceD2D::LineTo(int x_, int y_) { + if (pRenderTarget) { + int xDiff = x_ - x; + int xDelta = Delta(xDiff); + int yDiff = y_ - y; + int yDelta = Delta(yDiff); + if ((xDiff == 0) || (yDiff == 0)) { + // Horizontal or vertical lines can be more precisely drawn as a filled rectangle + int xEnd = x_ - xDelta; + int left = Platform::Minimum(x, xEnd); + int width = abs(x - xEnd) + 1; + int yEnd = y_ - yDelta; + int top = Platform::Minimum(y, yEnd); + int height = abs(y - yEnd) + 1; + D2D1_RECT_F rectangle1 = D2D1::RectF(left, top, left+width, top+height); + pRenderTarget->FillRectangle(&rectangle1, pBrush); + } else if ((abs(xDiff) == abs(yDiff))) { + // 45 degree slope + pRenderTarget->DrawLine(D2D1::Point2F(x + 0.5, y + 0.5), + D2D1::Point2F(x_ + 0.5 - xDelta, y_ + 0.5 - yDelta), pBrush); + } else { + // Line has a different slope so difficult to avoid last pixel + pRenderTarget->DrawLine(D2D1::Point2F(x + 0.5, y + 0.5), + D2D1::Point2F(x_ + 0.5, y_ + 0.5), pBrush); + } + x = x_; + y = y_; + } +} + +void SurfaceD2D::Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back) { + if (pRenderTarget) { + ID2D1Factory *pFactory = 0; + pRenderTarget->GetFactory(&pFactory); + ID2D1PathGeometry *geometry=0; + HRESULT hr = pFactory->CreatePathGeometry(&geometry); + if (SUCCEEDED(hr)) { + ID2D1GeometrySink *sink = 0; + hr = geometry->Open(&sink); + if (SUCCEEDED(hr)) { + sink->BeginFigure(D2D1::Point2F(pts[0].x + 0.5f, pts[0].y + 0.5f), D2D1_FIGURE_BEGIN_FILLED); + for (size_t i=1; i<static_cast<size_t>(npts); i++) { + sink->AddLine(D2D1::Point2F(pts[i].x + 0.5f, pts[i].y + 0.5f)); + } + sink->EndFigure(D2D1_FIGURE_END_CLOSED); + sink->Close(); + sink->Release(); + + D2DPenColour(back); + pRenderTarget->FillGeometry(geometry,pBrush); + D2DPenColour(fore); + pRenderTarget->DrawGeometry(geometry,pBrush); + } + + geometry->Release(); + } + } +} + +void SurfaceD2D::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) { + if (pRenderTarget) { + D2DPenColour(back); + D2D1_RECT_F rectangle1 = D2D1::RectF(RoundFloat(rc.left) + 0.5, rc.top+0.5, RoundFloat(rc.right) - 0.5, rc.bottom-0.5); + D2DPenColour(back); + pRenderTarget->FillRectangle(&rectangle1, pBrush); + D2DPenColour(fore); + pRenderTarget->DrawRectangle(&rectangle1, pBrush); + } +} + +void SurfaceD2D::FillRectangle(PRectangle rc, ColourAllocated back) { + if (pRenderTarget) { + D2DPenColour(back); + D2D1_RECT_F rectangle1 = D2D1::RectF(RoundFloat(rc.left), rc.top, RoundFloat(rc.right), rc.bottom); + pRenderTarget->FillRectangle(&rectangle1, pBrush); + } +} + +void SurfaceD2D::FillRectangle(PRectangle rc, Surface &surfacePattern) { + SurfaceD2D &surfOther = static_cast<SurfaceD2D &>(surfacePattern); + surfOther.FlushDrawing(); + ID2D1Bitmap *pBitmap = NULL; + ID2D1BitmapRenderTarget *pCompatibleRenderTarget = reinterpret_cast<ID2D1BitmapRenderTarget *>( + surfOther.pRenderTarget); + HRESULT hr = pCompatibleRenderTarget->GetBitmap(&pBitmap); + if (SUCCEEDED(hr)) { + ID2D1BitmapBrush *pBitmapBrush = NULL; + D2D1_BITMAP_BRUSH_PROPERTIES brushProperties = + D2D1::BitmapBrushProperties(D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP, + D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR); + // Create the bitmap brush. + hr = pRenderTarget->CreateBitmapBrush(pBitmap, brushProperties, &pBitmapBrush); + pBitmap->Release(); + if (SUCCEEDED(hr)) { + pRenderTarget->FillRectangle( + D2D1::RectF(rc.left, rc.top, rc.right, rc.bottom), + pBitmapBrush); + pBitmapBrush->Release(); + } + } +} + +void SurfaceD2D::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back) { + if (pRenderTarget) { + D2D1_ROUNDED_RECT roundedRectFill = D2D1::RoundedRect( + D2D1::RectF(rc.left+1.0, rc.top+1.0, rc.right-1.0, rc.bottom-1.0), + 8, 8); + D2DPenColour(back); + pRenderTarget->FillRoundedRectangle(roundedRectFill, pBrush); + + D2D1_ROUNDED_RECT roundedRect = D2D1::RoundedRect( + D2D1::RectF(rc.left + 0.5, rc.top+0.5, rc.right - 0.5, rc.bottom-0.5), + 8, 8); + D2DPenColour(fore); + pRenderTarget->DrawRoundedRectangle(roundedRect, pBrush); + } +} + +void SurfaceD2D::AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill, + ColourAllocated outline, int alphaOutline, int /* flags*/ ) { + if (pRenderTarget) { + D2D1_ROUNDED_RECT roundedRectFill = D2D1::RoundedRect( + D2D1::RectF(rc.left+1.0, rc.top+1.0, rc.right-1.0, rc.bottom-1.0), + cornerSize, cornerSize); + D2DPenColour(fill, alphaFill); + pRenderTarget->FillRoundedRectangle(roundedRectFill, pBrush); + + D2D1_ROUNDED_RECT roundedRect = D2D1::RoundedRect( + D2D1::RectF(rc.left + 0.5, rc.top+0.5, rc.right - 0.5, rc.bottom-0.5), + cornerSize, cornerSize); + D2DPenColour(outline, alphaOutline); + pRenderTarget->DrawRoundedRectangle(roundedRect, pBrush); + } +} + +void SurfaceD2D::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) { + if (pRenderTarget) { + if (rc.Width() > width) + rc.left += (rc.Width() - width) / 2; + rc.right = rc.left + width; + if (rc.Height() > height) + rc.top += (rc.Height() - height) / 2; + rc.bottom = rc.top + height; + + std::vector<unsigned char> image(height * width * 4); + for (int y=0; y<height; y++) { + for (int x=0; x<width; x++) { + unsigned char *pixel = &image[0] + (y*width+x) * 4; + unsigned char alpha = pixelsImage[3]; + // Input is RGBA, output is BGRA with premultiplied alpha + pixel[2] = (*pixelsImage++) * alpha / 255; + pixel[1] = (*pixelsImage++) * alpha / 255; + pixel[0] = (*pixelsImage++) * alpha / 255; + pixel[3] = *pixelsImage++; + } + } + + ID2D1Bitmap *bitmap = 0; + D2D1_SIZE_U size = D2D1::SizeU(width, height); + D2D1_BITMAP_PROPERTIES props = {{DXGI_FORMAT_B8G8R8A8_UNORM, + D2D1_ALPHA_MODE_PREMULTIPLIED}, 72.0, 72.0}; + HRESULT hr = pRenderTarget->CreateBitmap(size, &image[0], + width * 4, &props, &bitmap); + if (SUCCEEDED(hr)) { + D2D1_RECT_F rcDestination = {rc.left, rc.top, rc.right, rc.bottom}; + pRenderTarget->DrawBitmap(bitmap, rcDestination); + } + bitmap->Release(); + } +} + +void SurfaceD2D::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) { + if (pRenderTarget) { + FLOAT radius = rc.Width() / 2.0f - 1.0f; + D2D1_ELLIPSE ellipse = D2D1::Ellipse( + D2D1::Point2F((rc.left + rc.right) / 2.0f, (rc.top + rc.bottom) / 2.0f), + radius,radius); + + PenColour(back); + pRenderTarget->FillEllipse(ellipse, pBrush); + PenColour(fore); + pRenderTarget->DrawEllipse(ellipse, pBrush); + } +} + +void SurfaceD2D::Copy(PRectangle rc, Point from, Surface &surfaceSource) { + SurfaceD2D &surfOther = static_cast<SurfaceD2D &>(surfaceSource); + surfOther.FlushDrawing(); + ID2D1BitmapRenderTarget *pCompatibleRenderTarget = reinterpret_cast<ID2D1BitmapRenderTarget *>( + surfOther.pRenderTarget); + ID2D1Bitmap *pBitmap = NULL; + HRESULT hr = pCompatibleRenderTarget->GetBitmap(&pBitmap); + if (SUCCEEDED(hr)) { + D2D1_RECT_F rcDestination = {rc.left, rc.top, rc.right, rc.bottom}; + D2D1_RECT_F rcSource = {from.x, from.y, from.x + rc.Width(), from.y + rc.Height()}; + pRenderTarget->DrawBitmap(pBitmap, rcDestination, 1.0f, + D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR, rcSource); + pRenderTarget->Flush(); + pBitmap->Release(); + } +} + +void SurfaceD2D::DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, UINT) { + SetFont(font_); + RECT rcw = RectFromPRectangle(rc); + + // Use Unicode calls + const TextWide tbuf(s, len, unicodeMode, codePage); + if (pRenderTarget && pTextFormat && pBrush) { + + // Explicitly creating a text layout appears a little faster + IDWriteTextLayout *pTextLayout; + HRESULT hr = pIDWriteFactory->CreateTextLayout(tbuf.buffer, tbuf.tlen, pTextFormat, + rc.Width(), rc.Height(), &pTextLayout); + if (SUCCEEDED(hr)) { + D2D1_POINT_2F origin = {rc.left, ybase-yAscent}; + pRenderTarget->DrawTextLayout(origin, pTextLayout, pBrush, D2D1_DRAW_TEXT_OPTIONS_NONE); + } else { + D2D1_RECT_F layoutRect = D2D1::RectF( + static_cast<FLOAT>(rcw.left) / dpiScaleX, + static_cast<FLOAT>(ybase-yAscent) / dpiScaleY, + static_cast<FLOAT>(rcw.right + 1) / dpiScaleX, + static_cast<FLOAT>(rcw.bottom) / dpiScaleY); + pRenderTarget->DrawText(tbuf.buffer, tbuf.tlen, pTextFormat, layoutRect, pBrush, D2D1_DRAW_TEXT_OPTIONS_NONE); + } + } +} + +void SurfaceD2D::DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, + ColourAllocated fore, ColourAllocated back) { + if (pRenderTarget) { + FillRectangle(rc, back); + D2DPenColour(fore); + DrawTextCommon(rc, font_, ybase, s, len, ETO_OPAQUE); + } +} + +void SurfaceD2D::DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, + ColourAllocated fore, ColourAllocated back) { + if (pRenderTarget) { + FillRectangle(rc, back); + D2DPenColour(fore); + DrawTextCommon(rc, font_, ybase, s, len, ETO_OPAQUE | ETO_CLIPPED); + } +} + +void SurfaceD2D::DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, + ColourAllocated fore) { + // Avoid drawing spaces in transparent mode + for (int i=0;i<len;i++) { + if (s[i] != ' ') { + if (pRenderTarget) { + D2DPenColour(fore); + DrawTextCommon(rc, font_, ybase, s, len, 0); + } + return; + } + } +} + +XYPOSITION SurfaceD2D::WidthText(Font &font_, const char *s, int len) { + FLOAT width = 1.0; + SetFont(font_); + const TextWide tbuf(s, len, unicodeMode, codePage); + if (pIDWriteFactory && pTextFormat) { + // Create a layout + IDWriteTextLayout *pTextLayout = 0; + HRESULT hr = pIDWriteFactory->CreateTextLayout(tbuf.buffer, tbuf.tlen, pTextFormat, 1000.0, 1000.0, &pTextLayout); + if (SUCCEEDED(hr)) { + DWRITE_TEXT_METRICS textMetrics; + pTextLayout->GetMetrics(&textMetrics); + width = textMetrics.widthIncludingTrailingWhitespace; + pTextLayout->Release(); + } + } + return int(width + 0.5); +} + +void SurfaceD2D::MeasureWidths(Font &font_, const char *s, int len, XYPOSITION *positions) { + SetFont(font_); + int fit = 0; + const TextWide tbuf(s, len, unicodeMode, codePage); + TextPositions poses(tbuf.tlen); + fit = tbuf.tlen; + const int clusters = 1000; + DWRITE_CLUSTER_METRICS clusterMetrics[clusters]; + UINT32 count = 0; + if (pIDWriteFactory && pTextFormat) { + SetFont(font_); + // Create a layout + IDWriteTextLayout *pTextLayout = 0; + HRESULT hr = pIDWriteFactory->CreateTextLayout(tbuf.buffer, tbuf.tlen, pTextFormat, 10000.0, 1000.0, &pTextLayout); + if (!SUCCEEDED(hr)) + return; + // For now, assuming WCHAR == cluster + pTextLayout->GetClusterMetrics(clusterMetrics, clusters, &count); + FLOAT position = 0.0f; + size_t ti=0; + for (size_t ci=0;ci<count;ci++) { + position += clusterMetrics[ci].width; + for (size_t inCluster=0; inCluster<clusterMetrics[ci].length; inCluster++) { + //poses.buffer[ti++] = int(position + 0.5); + poses.buffer[ti++] = position; + } + } + PLATFORM_ASSERT(ti == static_cast<size_t>(tbuf.tlen)); + pTextLayout->Release(); + } + if (unicodeMode) { + // Map the widths given for UTF-16 characters back onto the UTF-8 input string + int ui=0; + const unsigned char *us = reinterpret_cast<const unsigned char *>(s); + int i=0; + while (ui<fit) { + unsigned char uch = us[i]; + unsigned int lenChar = 1; + if (uch >= (0x80 + 0x40 + 0x20 + 0x10)) { + lenChar = 4; + ui++; + } else if (uch >= (0x80 + 0x40 + 0x20)) { + lenChar = 3; + } else if (uch >= (0x80)) { + lenChar = 2; + } + for (unsigned int bytePos=0; (bytePos<lenChar) && (i<len); bytePos++) { + positions[i++] = poses.buffer[ui]; + } + ui++; + } + int lastPos = 0; + if (i > 0) + lastPos = positions[i-1]; + while (i<len) { + positions[i++] = lastPos; + } + } else if (codePage == 0) { + + // One character per position + PLATFORM_ASSERT(len == tbuf.tlen); + for (size_t kk=0;kk<static_cast<size_t>(len);kk++) { + positions[kk] = poses.buffer[kk]; + } + + } else { + + // May be more than one byte per position + int ui = 0; + for (int i=0;i<len;) { + if (::IsDBCSLeadByteEx(codePage, s[i])) { + positions[i] = poses.buffer[ui]; + positions[i+1] = poses.buffer[ui]; + i += 2; + } else { + positions[i] = poses.buffer[ui]; + i++; + } + + ui++; + } + } +} + +XYPOSITION SurfaceD2D::WidthChar(Font &font_, char ch) { + FLOAT width = 1.0; + SetFont(font_); + if (pIDWriteFactory && pTextFormat) { + // Create a layout + IDWriteTextLayout *pTextLayout = 0; + const WCHAR wch = ch; + HRESULT hr = pIDWriteFactory->CreateTextLayout(&wch, 1, pTextFormat, 1000.0, 1000.0, &pTextLayout); + if (SUCCEEDED(hr)) { + DWRITE_TEXT_METRICS textMetrics; + pTextLayout->GetMetrics(&textMetrics); + width = textMetrics.widthIncludingTrailingWhitespace; + pTextLayout->Release(); + } + } + return int(width + 0.5); +} + +XYPOSITION SurfaceD2D::Ascent(Font &font_) { + SetFont(font_); + return ceil(yAscent); +} + +XYPOSITION SurfaceD2D::Descent(Font &font_) { + SetFont(font_); + return ceil(yDescent); +} + +XYPOSITION SurfaceD2D::InternalLeading(Font &) { + return 0; +} + +XYPOSITION SurfaceD2D::ExternalLeading(Font &) { + return 1; +} + +XYPOSITION SurfaceD2D::Height(Font &font_) { + return Ascent(font_) + Descent(font_); +} + +XYPOSITION SurfaceD2D::AverageCharWidth(Font &font_) { + FLOAT width = 1.0; + SetFont(font_); + if (pIDWriteFactory && pTextFormat) { + // Create a layout + IDWriteTextLayout *pTextLayout = 0; + const WCHAR wszAllAlpha[] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + HRESULT hr = pIDWriteFactory->CreateTextLayout(wszAllAlpha, wcslen(wszAllAlpha), pTextFormat, 1000.0, 1000.0, &pTextLayout); + if (SUCCEEDED(hr)) { + DWRITE_TEXT_METRICS textMetrics; + pTextLayout->GetMetrics(&textMetrics); + width = textMetrics.width / wcslen(wszAllAlpha); + pTextLayout->Release(); + } + } + return int(width + 0.5); +} + +int SurfaceD2D::SetPalette(Palette *, bool) { + return 0; +} + +void SurfaceD2D::SetClip(PRectangle rc) { + if (pRenderTarget) { + D2D1_RECT_F rcClip = {rc.left, rc.top, rc.right, rc.bottom}; + pRenderTarget->PushAxisAlignedClip(rcClip, D2D1_ANTIALIAS_MODE_ALIASED); + clipsActive++; + } +} + +void SurfaceD2D::FlushCachedState() { +} + +void SurfaceD2D::SetUnicodeMode(bool unicodeMode_) { + unicodeMode=unicodeMode_; +} + +void SurfaceD2D::SetDBCSMode(int codePage_) { + // No action on window as automatically handled by system. + codePage = codePage_; +} + +Surface *Surface::Allocate(int technology) { + if (technology == SCWIN_TECH_GDI) + return new SurfaceGDI; + else + return new SurfaceD2D; } Window::~Window() { @@ -1092,8 +1902,7 @@ void Window::SetPositionRelative(PRectangle rc, Window w) { #ifdef MONITOR_DEFAULTTONULL // We're using the stub functionality of MultiMon.h to decay gracefully on machines // (ie, pre Win2000, Win95) that do not support the newer functions. - RECT rcMonitor; - memcpy(&rcMonitor, &rc, sizeof(rcMonitor)); // RECT and Rectangle are the same really. + RECT rcMonitor = {rc.left, rc.top, rc.right, rc.bottom}; MONITORINFO mi = {0}; mi.cbSize = sizeof(mi); @@ -1365,6 +2174,7 @@ ListBox::~ListBox() { class ListBoxX : public ListBox { int lineHeight; FontID fontCopy; + int technology; RGBAImageSet images; LineToItem lti; HWND lb; @@ -1407,7 +2217,7 @@ class ListBoxX : public ListBox { static const Point ImageInset; // Padding around image public: - ListBoxX() : lineHeight(10), fontCopy(0), lb(0), unicodeMode(false), + ListBoxX() : lineHeight(10), fontCopy(0), technology(0), lb(0), unicodeMode(false), desiredVisibleRows(5), maxItemCharacters(0), aveCharWidth(8), parent(NULL), ctrlID(0), doubleClickAction(NULL), doubleClickActionData(NULL), widestItem(NULL), maxCharWidth(1), resizeHit(0), wheelDelta(0) { @@ -1419,7 +2229,7 @@ public: } } virtual void SetFont(Font &font); - virtual void Create(Window &parent, int ctrlID, Point location_, int lineHeight_, bool unicodeMode_); + virtual void Create(Window &parent, int ctrlID, Point location_, int lineHeight_, bool unicodeMode_, int technology_); virtual void SetAverageCharWidth(int width); virtual void SetVisibleRows(int rows); virtual int GetVisibleRows() const; @@ -1454,12 +2264,13 @@ ListBox *ListBox::Allocate() { return lb; } -void ListBoxX::Create(Window &parent_, int ctrlID_, Point location_, int lineHeight_, bool unicodeMode_) { +void ListBoxX::Create(Window &parent_, int ctrlID_, Point location_, int lineHeight_, bool unicodeMode_, int technology_) { parent = &parent_; ctrlID = ctrlID_; location = location_; lineHeight = lineHeight_; unicodeMode = unicodeMode_; + technology = technology_; HWND hwndParent = reinterpret_cast<HWND>(parent->GetID()); HINSTANCE hinstanceParent = GetWindowInstance(hwndParent); // Window created as popup so not clipped within parent client area @@ -1471,17 +2282,19 @@ void ListBoxX::Create(Window &parent_, int ctrlID_, Point location_, int lineHei hinstanceParent, this); - ::MapWindowPoints(hwndParent, NULL, reinterpret_cast<POINT*>(&location), 1); + POINT locationw = {location.x, location.y}; + ::MapWindowPoints(hwndParent, NULL, &locationw, 1); + location = Point(locationw.x, locationw.y); } void ListBoxX::SetFont(Font &font) { - LOGFONT lf; - if (0 != ::GetObject(font.GetID(), sizeof(lf), &lf)) { + if (font.GetID()) { if (fontCopy) { ::DeleteObject(fontCopy); fontCopy = 0; } - fontCopy = ::CreateFontIndirect(&lf); + FormatAndMetrics *pfm = reinterpret_cast<FormatAndMetrics *>(font.GetID()); + fontCopy = pfm->HFont(); ::SendMessage(lb, WM_SETFONT, reinterpret_cast<WPARAM>(fontCopy), 0); } } @@ -1650,16 +2463,46 @@ void ListBoxX::Draw(DRAWITEMSTRUCT *pDrawItem) { // Draw the image, if any RGBAImage *pimage = images.Get(pixId); if (pimage) { - Surface *surfaceItem = Surface::Allocate(); + Surface *surfaceItem = Surface::Allocate(technology); if (surfaceItem) { - surfaceItem->Init(pDrawItem->hDC, pDrawItem->hwndItem); - int left = pDrawItem->rcItem.left + ItemInset.x + ImageInset.x; - PRectangle rcImage(left, pDrawItem->rcItem.top, - left + images.GetWidth(), pDrawItem->rcItem.bottom); - surfaceItem->DrawRGBAImage(rcImage, - pimage->GetWidth(), pimage->GetHeight(), pimage->Pixels()); - delete surfaceItem; - ::SetTextAlign(pDrawItem->hDC, TA_TOP); + if (technology == SCWIN_TECH_GDI) { + surfaceItem->Init(pDrawItem->hDC, pDrawItem->hwndItem); + int left = pDrawItem->rcItem.left + ItemInset.x + ImageInset.x; + PRectangle rcImage(left, pDrawItem->rcItem.top, + left + images.GetWidth(), pDrawItem->rcItem.bottom); + surfaceItem->DrawRGBAImage(rcImage, + pimage->GetWidth(), pimage->GetHeight(), pimage->Pixels()); + delete surfaceItem; + ::SetTextAlign(pDrawItem->hDC, TA_TOP); + } else { + D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties( + D2D1_RENDER_TARGET_TYPE_DEFAULT, + D2D1::PixelFormat( + DXGI_FORMAT_B8G8R8A8_UNORM, + D2D1_ALPHA_MODE_IGNORE), + 0, + 0, + D2D1_RENDER_TARGET_USAGE_NONE, + D2D1_FEATURE_LEVEL_DEFAULT + ); + ID2D1DCRenderTarget *pDCRT = 0; + HRESULT hr = pD2DFactory->CreateDCRenderTarget(&props, &pDCRT); + RECT rcWindow; + GetClientRect(pDrawItem->hwndItem, &rcWindow); + hr = pDCRT->BindDC(pDrawItem->hDC, &rcWindow); + if (SUCCEEDED(hr)) { + surfaceItem->Init(pDCRT, pDrawItem->hwndItem); + pDCRT->BeginDraw(); + int left = pDrawItem->rcItem.left + ItemInset.x + ImageInset.x; + PRectangle rcImage(left, pDrawItem->rcItem.top, + left + images.GetWidth(), pDrawItem->rcItem.bottom); + surfaceItem->DrawRGBAImage(rcImage, + pimage->GetWidth(), pimage->GetHeight(), pimage->Pixels()); + delete surfaceItem; + pDCRT->EndDraw(); + pDCRT->Release(); + } + } } } } @@ -1726,7 +2569,9 @@ void ListBoxX::SetList(const char *list, char separator, char typesep) { } void ListBoxX::AdjustWindowRect(PRectangle *rc) const { - ::AdjustWindowRectEx(reinterpret_cast<RECT*>(rc), WS_THICKFRAME, false, WS_EX_WINDOWEDGE); + RECT rcw = {rc->left, rc->top, rc->right, rc->bottom }; + ::AdjustWindowRectEx(&rcw, WS_THICKFRAME, false, WS_EX_WINDOWEDGE); + *rc = PRectangle(rcw.left, rcw.top, rcw.right, rcw.bottom); } int ListBoxX::ItemHeight() const { @@ -1767,8 +2612,9 @@ void ListBoxX::SetRedraw(bool on) { void ListBoxX::ResizeToCursor() { PRectangle rc = GetPosition(); - Point pt; - ::GetCursorPos(reinterpret_cast<POINT*>(&pt)); + POINT ptw; + ::GetCursorPos(&ptw); + Point pt(ptw.x, ptw.y); pt.x += dragOffset.x; pt.y += dragOffset.y; diff --git a/win32/PlatWin.h b/win32/PlatWin.h new file mode 100644 index 000000000..dc3f8e432 --- /dev/null +++ b/win32/PlatWin.h @@ -0,0 +1,13 @@ +// Scintilla source code edit control +/** @file PlatWin.h + ** Implementation of platform facilities on Windows. + **/ +// Copyright 1998-2011 by Neil Hodgson <neilh@scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. + +extern bool IsNT(); +extern void Platform_Initialise(void *hInstance); +extern void Platform_Finalise(); +extern bool LoadD2D(); +extern ID2D1Factory *pD2DFactory; +extern IDWriteFactory *pIDWriteFactory; diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx index d1f450479..a3c141aff 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -24,6 +24,9 @@ #include <richedit.h> #include <windowsx.h> +#include <d2d1.h> +#include <dwrite.h> + #include "Platform.h" #include "ILexer.h" @@ -54,6 +57,7 @@ #include "Editor.h" #include "ScintillaBase.h" #include "UniConversion.h" +#include "PlatWin.h" #ifdef SCI_LEXER #include "ExternalLexer.h" @@ -87,11 +91,6 @@ #define SC_WIN_IDLE 5001 -// Functions imported from PlatWin -extern bool IsNT(); -extern void Platform_Initialise(void *hInstance); -extern void Platform_Finalise(); - typedef BOOL (WINAPI *TrackMouseEventSig)(LPTRACKMOUSEEVENT); // GCC has trouble with the standard COM ABI so do it the old C way with explicit vtables. @@ -197,6 +196,8 @@ class ScintillaWin : static HINSTANCE hInstance; + ID2D1HwndRenderTarget *pRenderTarget; + ScintillaWin(HWND hwnd); ScintillaWin(const ScintillaWin &); virtual ~ScintillaWin(); @@ -204,6 +205,8 @@ class ScintillaWin : virtual void Initialise(); virtual void Finalise(); + void EnsureRenderTarget(); + void DropRenderTarget(); HWND MainHWND(); static sptr_t DirectFunction( @@ -350,6 +353,8 @@ ScintillaWin::ScintillaWin(HWND hwnd) { sysCaretWidth = 0; sysCaretHeight = 0; + pRenderTarget = 0; + keysAlwaysUnicode = false; caret.period = ::GetCaretBlinkTime(); @@ -384,12 +389,46 @@ void ScintillaWin::Finalise() { ScintillaBase::Finalise(); SetTicking(false); SetIdle(false); + DropRenderTarget(); ::RevokeDragDrop(MainHWND()); if (SUCCEEDED(hrOle)) { ::OleUninitialize(); } } +void ScintillaWin::EnsureRenderTarget() { + if (pD2DFactory && !pRenderTarget) { + RECT rc; + HWND hw = MainHWND(); + GetClientRect(hw, &rc); + + D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top); + + // Create a Direct2D render target. +#if 1 + pD2DFactory->CreateHwndRenderTarget( + D2D1::RenderTargetProperties(), + D2D1::HwndRenderTargetProperties(hw, size), + &pRenderTarget); +#else + pD2DFactory->CreateHwndRenderTarget( + D2D1::RenderTargetProperties( + D2D1_RENDER_TARGET_TYPE_DEFAULT , + D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED), + 96.0f, 96.0f, D2D1_RENDER_TARGET_USAGE_NONE, D2D1_FEATURE_LEVEL_DEFAULT), + D2D1::HwndRenderTargetProperties(hw, size), + &pRenderTarget); +#endif + } +} + +void ScintillaWin::DropRenderTarget() { + if (pRenderTarget) { + pRenderTarget->Release(); + pRenderTarget = 0; + } +} + HWND ScintillaWin::MainHWND() { return reinterpret_cast<HWND>(wMain.GetID()); } @@ -505,18 +544,35 @@ LRESULT ScintillaWin::WndPaint(uptr_t wParam) { pps = &ps; ::BeginPaint(MainHWND(), pps); } - AutoSurface surfaceWindow(pps->hdc, this); - if (surfaceWindow) { - rcPaint = PRectangle(pps->rcPaint.left, pps->rcPaint.top, pps->rcPaint.right, pps->rcPaint.bottom); - PRectangle rcClient = GetClientRectangle(); - paintingAllText = rcPaint.Contains(rcClient); - if (paintingAllText) { - //Platform::DebugPrintf("Performing full text paint\n"); - } else { - //Platform::DebugPrintf("Performing partial paint %d .. %d\n", rcPaint.top, rcPaint.bottom); + if (technology == SC_TECHNOLOGY_DEFAULT) { + AutoSurface surfaceWindow(pps->hdc, this); + if (surfaceWindow) { + rcPaint = PRectangle(pps->rcPaint.left, pps->rcPaint.top, pps->rcPaint.right, pps->rcPaint.bottom); + PRectangle rcClient = GetClientRectangle(); + paintingAllText = rcPaint.Contains(rcClient); + Paint(surfaceWindow, rcPaint); + surfaceWindow->Release(); + } + } else { + EnsureRenderTarget(); + AutoSurface surfaceWindow(pRenderTarget, this); + if (surfaceWindow) { + pRenderTarget->BeginDraw(); + rcPaint = PRectangle(pps->rcPaint.left, pps->rcPaint.top, pps->rcPaint.right, pps->rcPaint.bottom); + PRectangle rcClient = GetClientRectangle(); + paintingAllText = rcPaint.Contains(rcClient); + if (paintingAllText) { + //Platform::DebugPrintf("Performing full text paint\n"); + } else { + //Platform::DebugPrintf("Performing partial paint %d .. %d\n", rcPaint.top, rcPaint.bottom); + } + Paint(surfaceWindow, rcPaint); + surfaceWindow->Release(); + HRESULT hr = pRenderTarget->EndDraw(); + if (hr == D2DERR_RECREATE_TARGET) { + DropRenderTarget(); + } } - Paint(surfaceWindow, rcPaint); - surfaceWindow->Release(); } if (hRgnUpdate) { ::DeleteRgn(hRgnUpdate); @@ -674,6 +730,7 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam break; case WM_SIZE: { + DropRenderTarget(); //Platform::DebugPrintf("Scintilla WM_SIZE %d %d\n", LoWord(lParam), HiWord(lParam)); ChangeSize(); } @@ -1085,6 +1142,22 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam case SCI_GETKEYSUNICODE: return keysAlwaysUnicode; + + case SCI_SETTECHNOLOGY: + if ((wParam == SC_TECHNOLOGY_DEFAULT) || (wParam == SC_TECHNOLOGY_DIRECTWRITE)) { + if (technology != static_cast<int>(wParam)) { + if (static_cast<int>(wParam) == SC_TECHNOLOGY_DIRECTWRITE) { + if (!LoadD2D()) + // Failed to load Direct2D or DirectWrite so no effect + return 0; + } + technology = wParam; + // Invalidate all cached information including layout. + DropGraphics(true); + InvalidateStyleRedraw(); + } + } + break; #ifdef SCI_LEXER case SCI_LOADLEXERLIBRARY: @@ -1196,11 +1269,12 @@ bool ScintillaWin::PaintContains(PRectangle rc) { return contains; } -void ScintillaWin::ScrollText(int linesToMove) { +void ScintillaWin::ScrollText(int /* linesToMove */) { //Platform::DebugPrintf("ScintillaWin::ScrollText %d\n", linesToMove); - ::ScrollWindow(MainHWND(), 0, - vs.lineHeight * linesToMove, 0, 0); - ::UpdateWindow(MainHWND()); + //::ScrollWindow(MainHWND(), 0, + // vs.lineHeight * linesToMove, 0, 0); + //::UpdateWindow(MainHWND()); + Redraw(); } void ScintillaWin::UpdateSystemCaret() { @@ -2085,9 +2159,9 @@ void ScintillaWin::ImeStartComposition() { // The logfont for the IME is recreated here. int styleHere = (pdoc->StyleAt(sel.MainCaret())) & 31; LOGFONTA lf = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ""}; - int sizeZoomed = vs.styles[styleHere].size + vs.zoomLevel; - if (sizeZoomed <= 2) // Hangs if sizeZoomed <= 1 - sizeZoomed = 2; + int sizeZoomed = vs.styles[styleHere].size + vs.zoomLevel * SC_FONT_SIZE_MULTIPLIER; + if (sizeZoomed <= 2 * SC_FONT_SIZE_MULTIPLIER) // Hangs if sizeZoomed <= 1 + sizeZoomed = 2 * SC_FONT_SIZE_MULTIPLIER; AutoSurface surface(this); int deviceHeight = sizeZoomed; if (surface) { @@ -2095,7 +2169,7 @@ void ScintillaWin::ImeStartComposition() { } // The negative is to allow for leading lf.lfHeight = -(abs(deviceHeight)); - lf.lfWeight = vs.styles[styleHere].bold ? FW_BOLD : FW_NORMAL; + lf.lfWeight = vs.styles[styleHere].weight; lf.lfItalic = static_cast<BYTE>(vs.styles[styleHere].italic ? 1 : 0); lf.lfCharSet = DEFAULT_CHARSET; lf.lfFaceName[0] = '\0'; @@ -2290,7 +2364,9 @@ void ScintillaWin::HorizontalScrollMessage(WPARAM wParam) { HorizontalScrollTo(xPos); } -void ScintillaWin::RealizeWindowPalette(bool inBackGround) { +void ScintillaWin::RealizeWindowPalette(bool) { + // No support for palette with D2D +/* RefreshStyleData(); HDC hdc = ::GetDC(MainHWND()); // Select a stock font to prevent warnings from BoundsChecker @@ -2303,6 +2379,7 @@ void ScintillaWin::RealizeWindowPalette(bool inBackGround) { surfaceWindow->Release(); } ::ReleaseDC(MainHWND(), hdc); +*/ } /** @@ -2310,9 +2387,13 @@ void ScintillaWin::RealizeWindowPalette(bool inBackGround) { * This paint will not be abandoned. */ void ScintillaWin::FullPaint() { - HDC hdc = ::GetDC(MainHWND()); - FullPaintDC(hdc); - ::ReleaseDC(MainHWND(), hdc); + if (technology == SC_TECHNOLOGY_DEFAULT) { + HDC hdc = ::GetDC(MainHWND()); + FullPaintDC(hdc); + ::ReleaseDC(MainHWND(), hdc); + } else { + FullPaintDC(0); + } } /** @@ -2323,10 +2404,24 @@ void ScintillaWin::FullPaintDC(HDC hdc) { paintState = painting; rcPaint = GetClientRectangle(); paintingAllText = true; - AutoSurface surfaceWindow(hdc, this); - if (surfaceWindow) { - Paint(surfaceWindow, rcPaint); - surfaceWindow->Release(); + if (technology == SC_TECHNOLOGY_DEFAULT) { + AutoSurface surfaceWindow(hdc, this); + if (surfaceWindow) { + Paint(surfaceWindow, rcPaint); + surfaceWindow->Release(); + } + } else { + EnsureRenderTarget(); + AutoSurface surfaceWindow(pRenderTarget, this); + if (surfaceWindow) { + pRenderTarget->BeginDraw(); + Paint(surfaceWindow, rcPaint); + surfaceWindow->Release(); + HRESULT hr = pRenderTarget->EndDraw(); + if (hr == D2DERR_RECREATE_TARGET) { + DropRenderTarget(); + } + } } paintState = notPainting; } @@ -2698,14 +2793,31 @@ sptr_t PASCAL ScintillaWin::CTWndProc( } else if (iMessage == WM_PAINT) { PAINTSTRUCT ps; ::BeginPaint(hWnd, &ps); - Surface *surfaceWindow = Surface::Allocate(); + Surface *surfaceWindow = Surface::Allocate(sciThis->technology); if (surfaceWindow) { - surfaceWindow->Init(ps.hdc, hWnd); + ID2D1HwndRenderTarget *pCTRenderTarget = 0; + RECT rc; + GetClientRect(hWnd, &rc); + // Create a Direct2D render target. + if (sciThis->technology == SC_TECHNOLOGY_DEFAULT) { + surfaceWindow->Init(ps.hdc, hWnd); + } else { + pD2DFactory->CreateHwndRenderTarget( + D2D1::RenderTargetProperties(), + D2D1::HwndRenderTargetProperties(hWnd, D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)), + &pCTRenderTarget); + surfaceWindow->Init(pCTRenderTarget, hWnd); + pCTRenderTarget->BeginDraw(); + } surfaceWindow->SetUnicodeMode(SC_CP_UTF8 == sciThis->ct.codePage); surfaceWindow->SetDBCSMode(sciThis->ct.codePage); sciThis->ct.PaintCT(surfaceWindow); + if (pCTRenderTarget) + pCTRenderTarget->EndDraw(); surfaceWindow->Release(); delete surfaceWindow; + if (pCTRenderTarget) + pCTRenderTarget->Release(); } ::EndPaint(hWnd, &ps); return 0; |