aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--cocoa/PlatCocoa.h24
-rw-r--r--cocoa/PlatCocoa.mm40
-rw-r--r--cocoa/ScintillaTest/AppController.mm2
-rw-r--r--include/Platform.h51
-rw-r--r--src/Editor.cxx10
-rw-r--r--src/PositionCache.cxx14
-rw-r--r--src/PositionCache.h10
-rw-r--r--win32/PlatWin.cxx954
-rw-r--r--win32/ScintillaWin.cxx118
9 files changed, 747 insertions, 476 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 75803e33b..1972fa7a9 100644
--- a/cocoa/PlatCocoa.mm
+++ b/cocoa/PlatCocoa.mm
@@ -156,7 +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,
+void Font::Create(const char *faceName, int characterSet, float size, bool bold, bool italic,
int /* extraFontFlag */)
{
Release();
@@ -507,6 +507,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 +644,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 +842,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 +851,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 +919,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 +949,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 +968,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 +984,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 +1008,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 +1025,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 +1034,7 @@ int SurfaceImpl::Ascent(Font &font_) {
}
-int SurfaceImpl::Descent(Font &font_) {
+XYPOSITION SurfaceImpl::Descent(Font &font_) {
if (!font_.GetID())
return 1;
@@ -1037,11 +1043,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 +1056,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;
diff --git a/cocoa/ScintillaTest/AppController.mm b/cocoa/ScintillaTest/AppController.mm
index 4c8801a33..fbcdad9a8 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/include/Platform.h b/include/Platform.h
index b0f3de0dc..d4c6bbfec 100644
--- a/include/Platform.h
+++ b/include/Platform.h
@@ -9,6 +9,9 @@
#ifndef PLATFORM_H
#define PLATFORM_H
+#define XYPOSITION float
+//#define XYPOSITION int
+
// PLAT_GTK = GTK+ on Linux or Win32
// PLAT_GTK_WIN32 is defined additionally when running PLAT_GTK under Win32
// PLAT_WIN = Win32 API on Win32 OS
@@ -76,10 +79,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 +97,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 +124,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);
}
@@ -300,7 +303,7 @@ public:
Font();
virtual ~Font();
- virtual void Create(const char *faceName, int characterSet, int size,
+ virtual void Create(const char *faceName, int characterSet, float size,
bool bold, bool italic, int extraFontFlag=0);
virtual void Release();
@@ -349,18 +352,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;
diff --git a/src/Editor.cxx b/src/Editor.cxx
index 452666be7..f44279bbd 100644
--- a/src/Editor.cxx
+++ b/src/Editor.cxx
@@ -2216,7 +2216,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
+ XYPOSITION startsegx = 0; // Start of the current segment, in pixels
ll->positions[0] = 0;
unsigned int tabWidth = vstyle.spaceWidth * pdoc->tabInChars;
bool lastSegItalics = false;
@@ -2902,8 +2902,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 +3381,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
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/win32/PlatWin.cxx b/win32/PlatWin.cxx
index 6a2f103ba..acbb5f62d 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,30 @@ void Palette::Allocate(Window &) {
}
}
+static IDWriteFactory *pIDWriteFactory = 0;
+
+static void EnsureDWriteFactory() {
+ // Construct
+ if (!pIDWriteFactory) {
+ DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
+ __uuidof(IDWriteFactory),
+ reinterpret_cast<IUnknown**>(&pIDWriteFactory));
+ }
+}
+
+struct FormatAndBaseline {
+ IDWriteTextFormat *pTextFormat;
+ FLOAT baseline;
+ FormatAndBaseline(IDWriteTextFormat *pTextFormat_, FLOAT baseline_) :
+ pTextFormat(pTextFormat_), baseline(baseline_) {
+ }
+ ~FormatAndBaseline() {
+ pTextFormat->Release();
+ pTextFormat = 0;
+ baseline = 1;
+ }
+};
+
#ifndef CLEARTYPE_QUALITY
#define CLEARTYPE_QUALITY 5
#endif
@@ -247,28 +273,74 @@ class FontCached : Font {
int usage;
LOGFONTA lf;
int hash;
- FontCached(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_, int extraFontFlag_);
+ FontCached(const char *faceName_, int characterSet_, float size_, bool bold_, bool italic_, int extraFontFlag_);
~FontCached() {}
- bool SameAs(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_, int extraFontFlag_);
+ bool SameAs(const char *faceName_, int characterSet_, float size_, bool bold_, bool italic_, int extraFontFlag_);
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 char *faceName_, int characterSet_, float size_, bool bold_, bool italic_, int extraFontFlag_);
static void ReleaseId(FontID fid_);
};
FontCached *FontCached::first = 0;
-FontCached::FontCached(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_, int extraFontFlag_) :
+FontCached::FontCached(const char *faceName_, int characterSet_, float 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);
+ fid = 0;
+ EnsureDWriteFactory();
+ if (pIDWriteFactory) {
+#ifdef OLD_CODE
+ HFONT fontSave = static_cast<HFONT>(::SelectObject(hdc, font_.GetID()));
+ DWORD sizeOLTM = ::GetOutlineTextMetrics(hdc, NULL, NULL);
+ std::vector<char> vOLTM(sizeOLTM);
+ LPOUTLINETEXTMETRIC potm = reinterpret_cast<LPOUTLINETEXTMETRIC>(&vOLTM[0]);
+ DWORD worked = ::GetOutlineTextMetrics(hdc, sizeOLTM, potm);
+ ::SelectObject(hdc, fontSave);
+ if (!worked)
+ return;
+ const WCHAR *pwcFamily = reinterpret_cast<WCHAR *>(&vOLTM[reinterpret_cast<size_t>(potm->otmpFamilyName)]);
+ //const WCHAR *pwcFace = reinterpret_cast<WCHAR *>(&vOLTM[reinterpret_cast<size_t>(potm->otmpFaceName)]);
+ FLOAT fHeight = potm->otmTextMetrics.tmHeight * 72.0f / 96.0f;
+ bool italics = potm->otmTextMetrics.tmItalic != 0;
+ bool bold = potm->otmTextMetrics.tmWeight >= FW_BOLD;
+#endif
+ IDWriteTextFormat *pTextFormat;
+ const int faceSize = 200;
+ WCHAR wszFace[faceSize];
+ UTF16FromUTF8(faceName_, strlen(faceName_)+1, wszFace, faceSize);
+ FLOAT fHeight = size_;
+ if (fHeight > 2000)
+ fHeight = fHeight / 1000.0f;
+ HRESULT hr = pIDWriteFactory->CreateTextFormat(wszFace, NULL,
+ bold_ ? DWRITE_FONT_WEIGHT_SEMI_BOLD : DWRITE_FONT_WEIGHT_REGULAR,
+ italic_ ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL,
+ DWRITE_FONT_STRETCH_NORMAL, fHeight, L"en-us", &pTextFormat);
+ if (SUCCEEDED(hr)) {
+ const int maxLines = 2;
+ DWRITE_LINE_METRICS lineMetrics[maxLines];
+ UINT32 lineCount = 0;
+ FLOAT baseline = 1.0f;
+ IDWriteTextLayout *pTextLayout = 0;
+ HRESULT hr = pIDWriteFactory->CreateTextLayout(L"X", 1, pTextFormat,
+ 100.0f, 100.0f, &pTextLayout);
+ if (SUCCEEDED(hr)) {
+ hr = pTextLayout->GetLineMetrics(lineMetrics, maxLines, &lineCount);
+ if (SUCCEEDED(hr)) {
+ baseline = lineMetrics[0].baseline;
+ }
+ pTextLayout->Release();
+ }
+ fid = reinterpret_cast<void *>(new FormatAndBaseline(pTextFormat, baseline));
+ }
+ }
usage = 1;
}
-bool FontCached::SameAs(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_, int extraFontFlag_) {
+bool FontCached::SameAs(const char *faceName_, int characterSet_, float size_, bool bold_, bool italic_, int extraFontFlag_) {
return
(lf.lfHeight == -(abs(size_))) &&
(lf.lfWeight == (bold_ ? FW_BOLD : FW_NORMAL)) &&
@@ -279,12 +351,11 @@ bool FontCached::SameAs(const char *faceName_, int characterSet_, int size_, boo
}
void FontCached::Release() {
- if (fid)
- ::DeleteObject(fid);
+ delete reinterpret_cast<FormatAndBaseline *>(fid);
fid = 0;
}
-FontID FontCached::FindOrCreate(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_, int extraFontFlag_) {
+FontID FontCached::FindOrCreate(const char *faceName_, int characterSet_, float size_, bool bold_, bool italic_, int extraFontFlag_) {
FontID ret = 0;
::EnterCriticalSection(&crPlatformLock);
int hashFind = HashFont(faceName_, characterSet_, size_, bold_, italic_, extraFontFlag_);
@@ -335,27 +406,16 @@ Font::~Font() {
#define FONTS_CACHED
-void Font::Create(const char *faceName, int characterSet, int size,
+void Font::Create(const char *faceName, int characterSet, float size,
bool bold, bool italic, int extraFontFlag) {
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
}
void Font::Release() {
-#ifndef FONTS_CACHED
- if (fid)
- ::DeleteObject(fid);
-#else
if (fid)
FontCached::ReleaseId(fid);
-#endif
fid = 0;
}
@@ -367,23 +427,26 @@ class SurfaceImpl : public Surface {
bool unicodeMode;
HDC hdc;
bool hdcOwned;
- HPEN pen;
- HPEN penOld;
- HBRUSH brush;
- HBRUSH brushOld;
- HFONT font;
- HFONT fontOld;
- HBITMAP bitmap;
- HBITMAP bitmapOld;
- HPALETTE paletteOld;
int maxWidthMeasure;
int maxLenText;
+ int x, y;
int codePage;
// If 9x OS and current code page is same as ANSI code page.
bool win9xACPSame;
- void BrushColor(ColourAllocated back);
+ ID2D1RenderTarget *pRenderTarget;
+ bool ownRenderTarget;
+ bool needsEndDraw;
+ int clipsActive;
+
+ IDWriteTextFormat *pTextFormat;
+ FLOAT baseline;
+ ID2D1SolidColorBrush *pBrush;
+ float dpiScaleX;
+ float dpiScaleY;
+ bool hasBegun;
+
void SetFont(Font &font_);
// Private so SurfaceImpl objects can not be copied
@@ -393,13 +456,18 @@ public:
SurfaceImpl();
virtual ~SurfaceImpl();
+ void SetDWrite(HDC hdc);
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_);
@@ -415,19 +483,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,14 +509,13 @@ public:
} //namespace Scintilla
#endif
+#pragma comment(lib, "d2d1.lib")
+#pragma comment(lib, "dwrite.lib")
+
SurfaceImpl::SurfaceImpl() :
unicodeMode(false),
- hdc(0), hdcOwned(false),
- pen(0), penOld(0),
- brush(0), brushOld(0),
- font(0), fontOld(0),
- bitmap(0), bitmapOld(0),
- paletteOld(0) {
+ hdc(0), hdcOwned(false),
+ x(0), y(0), {
// Windows 9x has only a 16 bit coordinate system so break after 30000 pixels
maxWidthMeasure = IsNT() ? INT_MAX : 30000;
// There appears to be a 16 bit string length limit in GDI on NT and a limit of
@@ -457,6 +524,17 @@ SurfaceImpl::SurfaceImpl() :
codePage = 0;
win9xACPSame = false;
+
+ pRenderTarget = NULL;
+ ownRenderTarget = false;
+ needsEndDraw = false;
+ clipsActive = 0;
+ pTextFormat = NULL;
+ baseline = 1.0f;
+ pBrush = NULL;
+ dpiScaleX = 1.0;
+ dpiScaleY = 1.0;
+ hasBegun = false;
}
SurfaceImpl::~SurfaceImpl() {
@@ -464,102 +542,107 @@ SurfaceImpl::~SurfaceImpl() {
}
void SurfaceImpl::Release() {
- if (penOld) {
- ::SelectObject(reinterpret_cast<HDC>(hdc), penOld);
- ::DeleteObject(pen);
- penOld = 0;
- }
- pen = 0;
- if (brushOld) {
- ::SelectObject(reinterpret_cast<HDC>(hdc), brushOld);
- ::DeleteObject(brush);
- brushOld = 0;
- }
- brush = 0;
- if (fontOld) {
- // Fonts are not deleted as they are owned by a Font object
- ::SelectObject(reinterpret_cast<HDC>(hdc), fontOld);
- fontOld = 0;
- }
- font = 0;
- if (bitmapOld) {
- ::SelectObject(reinterpret_cast<HDC>(hdc), bitmapOld);
- ::DeleteObject(bitmap);
- bitmapOld = 0;
- }
- bitmap = 0;
- if (paletteOld) {
- // Palettes are not deleted as they are owned by a Palette object
- ::SelectPalette(reinterpret_cast<HDC>(hdc),
- reinterpret_cast<HPALETTE>(paletteOld), TRUE);
- paletteOld = 0;
- }
if (hdcOwned) {
::DeleteDC(reinterpret_cast<HDC>(hdc));
hdc = 0;
hdcOwned = false;
}
+
+ if (pBrush) {
+ pBrush->Release();
+ pBrush = 0;
+ }
+ if (pRenderTarget) {
+ while (clipsActive) {
+ pRenderTarget->PopAxisAlignedClip();
+ clipsActive--;
+ }
+ if (ownRenderTarget) {
+ pRenderTarget->Release();
+ }
+ pRenderTarget = 0;
+ }
+}
+
+// Ensures have pIDWriteFactory, and pRenderTarget
+// If any fail, pRenderTarget will be NULL
+void SurfaceImpl::SetDWrite(HDC hdc) {
+ // Construct
+ EnsureDWriteFactory();
+ dpiScaleX = GetDeviceCaps(hdc, LOGPIXELSX) / 96.0f;
+ dpiScaleY = GetDeviceCaps(hdc, LOGPIXELSY) / 96.0f;
}
bool SurfaceImpl::Initialised() {
- return hdc != 0;
+ return pRenderTarget != 0;
+}
+
+HRESULT SurfaceImpl::FlushDrawing() {
+ return pRenderTarget->Flush();
}
-void SurfaceImpl::Init(WindowID) {
+void SurfaceImpl::Init(WindowID wid) {
Release();
hdc = ::CreateCompatibleDC(NULL);
hdcOwned = true;
::SetTextAlign(reinterpret_cast<HDC>(hdc), TA_BASELINE);
+ RECT rc;
+ ::GetClientRect(reinterpret_cast<HWND>(wid), &rc);
+ SetDWrite(hdc);
}
void SurfaceImpl::Init(SurfaceID sid, WindowID) {
Release();
- hdc = reinterpret_cast<HDC>(sid);
+ hdc = ::CreateCompatibleDC(NULL);
+ hdcOwned = true;
+ pRenderTarget = reinterpret_cast<ID2D1HwndRenderTarget *>(sid);
::SetTextAlign(reinterpret_cast<HDC>(hdc), TA_BASELINE);
+ SetDWrite(hdc);
}
void SurfaceImpl::InitPixMap(int width, int height, Surface *surface_, WindowID) {
Release();
- hdc = ::CreateCompatibleDC(static_cast<SurfaceImpl *>(surface_)->hdc);
+ hdc = ::CreateCompatibleDC(NULL); // Just for measurement
hdcOwned = true;
- bitmap = ::CreateCompatibleBitmap(static_cast<SurfaceImpl *>(surface_)->hdc, width, height);
- bitmapOld = static_cast<HBITMAP>(::SelectObject(hdc, bitmap));
- ::SetTextAlign(reinterpret_cast<HDC>(hdc), TA_BASELINE);
-}
-
-void SurfaceImpl::PenColour(ColourAllocated fore) {
- if (pen) {
- ::SelectObject(hdc, penOld);
- ::DeleteObject(pen);
- pen = 0;
- penOld = 0;
+ SurfaceImpl *psurfOther = static_cast<SurfaceImpl *>(surface_);
+ ID2D1BitmapRenderTarget *pCompatibleRenderTarget = NULL;
+ HRESULT hr = psurfOther->pRenderTarget->CreateCompatibleRenderTarget(
+ D2D1::SizeF(width, height), &pCompatibleRenderTarget);
+ if (SUCCEEDED(hr)) {
+ pRenderTarget = pCompatibleRenderTarget;
+ pRenderTarget->BeginDraw();
+ ownRenderTarget = true;
+ needsEndDraw = true;
}
- pen = ::CreatePen(0,1,fore.AsLong());
- penOld = static_cast<HPEN>(::SelectObject(reinterpret_cast<HDC>(hdc), pen));
}
-void SurfaceImpl::BrushColor(ColourAllocated back) {
- if (brush) {
- ::SelectObject(hdc, brushOld);
- ::DeleteObject(brush);
- brush = 0;
- brushOld = 0;
+void SurfaceImpl::PenColour(ColourAllocated fore) {
+ D2DPenColour(fore);
+}
+
+void SurfaceImpl::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;
+ }
+ }
}
- // Only ever want pure, non-dithered brushes
- ColourAllocated colourNearest = ::GetNearestColor(hdc, back.AsLong());
- brush = ::CreateSolidBrush(colourNearest.AsLong());
- brushOld = static_cast<HBRUSH>(::SelectObject(hdc, brush));
}
void SurfaceImpl::SetFont(Font &font_) {
- if (font_.GetID() != font) {
- if (fontOld) {
- ::SelectObject(hdc, font_.GetID());
- } else {
- fontOld = static_cast<HFONT>(::SelectObject(hdc, font_.GetID()));
- }
- font = reinterpret_cast<HFONT>(font_.GetID());
- }
+ FormatAndBaseline *pfabl = reinterpret_cast<FormatAndBaseline *>(font_.GetID());
+ pTextFormat = pfabl->pTextFormat;
+ baseline = pfabl->baseline;
}
int SurfaceImpl::LogPixelsY() {
@@ -571,142 +654,160 @@ int SurfaceImpl::DeviceHeightFont(int points) {
}
void SurfaceImpl::MoveTo(int x_, int y_) {
- ::MoveToEx(hdc, x_, y_, 0);
+ 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 SurfaceImpl::LineTo(int x_, int y_) {
- ::LineTo(hdc, x_, 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 SurfaceImpl::Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back) {
- PenColour(fore);
- BrushColor(back);
- ::Polygon(hdc, reinterpret_cast<POINT *>(pts), npts);
+ 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 SurfaceImpl::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
- PenColour(fore);
- BrushColor(back);
- ::Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);
+ 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 SurfaceImpl::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);
- ::SetBkColor(hdc, back.AsLong());
- ::ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE, &rcw, TEXT(""), 0, NULL);
+ 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 SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) {
- HBRUSH br;
- if (static_cast<SurfaceImpl &>(surfacePattern).bitmap)
- br = ::CreatePatternBrush(static_cast<SurfaceImpl &>(surfacePattern).bitmap);
- else // Something is wrong so display in red
- br = ::CreateSolidBrush(RGB(0xff, 0, 0));
- RECT rcw = RectFromPRectangle(rc);
- ::FillRect(hdc, &rcw, br);
- ::DeleteObject(br);
+ SurfaceImpl &surfOther = static_cast<SurfaceImpl &>(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 SurfaceImpl::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
- PenColour(fore);
- BrushColor(back);
- ::RoundRect(hdc,
- rc.left + 1, rc.top,
- rc.right - 1, rc.bottom,
- 8, 8);
-}
-
-// Plot a point into a DWORD buffer symetrically to all 4 qudrants
-static void AllFour(DWORD *pixels, int width, int height, int x, int y, DWORD val) {
- pixels[y*width+x] = val;
- pixels[y*width+width-1-x] = val;
- pixels[(height-1-y)*width+x] = val;
- pixels[(height-1-y)*width+width-1-x] = val;
-}
-
-#ifndef AC_SRC_OVER
-#define AC_SRC_OVER 0x00
-#endif
-#ifndef AC_SRC_ALPHA
-#define AC_SRC_ALPHA 0x01
-#endif
+ 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);
-static DWORD dwordFromBGRA(byte b, byte g, byte r, byte a) {
- union {
- byte pixVal[4];
- DWORD val;
- } converter;
- converter.pixVal[0] = b;
- converter.pixVal[1] = g;
- converter.pixVal[2] = r;
- converter.pixVal[3] = a;
- return converter.val;
+ 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 SurfaceImpl::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));
- int width = rc.Width();
- int height = rc.Height();
- // Ensure not distorted too much by corners when small
- cornerSize = Platform::Minimum(cornerSize, (Platform::Minimum(width, height) / 2) - 2);
- BITMAPINFO bpih = {sizeof(BITMAPINFOHEADER), width, height, 1, 32, BI_RGB, 0, 0, 0, 0, 0};
- void *image = 0;
- HBITMAP hbmMem = CreateDIBSection(reinterpret_cast<HDC>(hMemDC), &bpih,
- DIB_RGB_COLORS, &image, NULL, 0);
-
- HBITMAP hbmOld = SelectBitmap(hMemDC, hbmMem);
-
- DWORD valEmpty = dwordFromBGRA(0,0,0,0);
- DWORD valFill = dwordFromBGRA(
- static_cast<byte>(GetBValue(fill.AsLong()) * alphaFill / 255),
- static_cast<byte>(GetGValue(fill.AsLong()) * alphaFill / 255),
- static_cast<byte>(GetRValue(fill.AsLong()) * alphaFill / 255),
- static_cast<byte>(alphaFill));
- DWORD valOutline = dwordFromBGRA(
- static_cast<byte>(GetBValue(outline.AsLong()) * alphaOutline / 255),
- static_cast<byte>(GetGValue(outline.AsLong()) * alphaOutline / 255),
- static_cast<byte>(GetRValue(outline.AsLong()) * alphaOutline / 255),
- static_cast<byte>(alphaOutline));
- DWORD *pixels = reinterpret_cast<DWORD *>(image);
- for (int y=0; y<height; y++) {
- for (int x=0; x<width; x++) {
- if ((x==0) || (x==width-1) || (y == 0) || (y == height-1)) {
- pixels[y*width+x] = valOutline;
- } else {
- pixels[y*width+x] = valFill;
- }
- }
- }
- for (int c=0;c<cornerSize; c++) {
- for (int x=0;x<c+1; x++) {
- AllFour(pixels, width, height, x, c-x, valEmpty);
- }
- }
- for (int x=1;x<cornerSize; x++) {
- AllFour(pixels, width, height, x, cornerSize-x, valOutline);
- }
+ 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);
- BLENDFUNCTION merge = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
-
- AlphaBlendFn(reinterpret_cast<HDC>(hdc), rc.left, rc.top, width, height, hMemDC, 0, 0, width, height, merge);
-
- SelectBitmap(hMemDC, hbmOld);
- ::DeleteObject(hbmMem);
- ::DeleteDC(hMemDC);
- } else {
- BrushColor(outline);
- RECT rcw = RectFromPRectangle(rc);
- FrameRect(hdc, &rcw, brush);
+ 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 SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) {
- if (AlphaBlendFn && rc.Width() > 0) {
- HDC hMemDC = ::CreateCompatibleDC(reinterpret_cast<HDC>(hdc));
+ if (pRenderTarget) {
if (rc.Width() > width)
rc.left += (rc.Width() - width) / 2;
rc.right = rc.left + width;
@@ -714,15 +815,10 @@ void SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height, const unsi
rc.top += (rc.Height() - height) / 2;
rc.bottom = rc.top + height;
- BITMAPINFO bpih = {sizeof(BITMAPINFOHEADER), width, height, 1, 32, BI_RGB, 0, 0, 0, 0, 0};
- unsigned char *image = 0;
- HBITMAP hbmMem = CreateDIBSection(reinterpret_cast<HDC>(hMemDC), &bpih,
- DIB_RGB_COLORS, reinterpret_cast<void **>(&image), NULL, 0);
- HBITMAP hbmOld = SelectBitmap(hMemDC, hbmMem);
-
- for (int y=height-1; y>=0; y--) {
+ 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 + (y*width+x) * 4;
+ 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;
@@ -731,28 +827,50 @@ void SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height, const unsi
pixel[3] = *pixelsImage++;
}
}
-
- BLENDFUNCTION merge = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
-
- AlphaBlendFn(reinterpret_cast<HDC>(hdc), rc.left, rc.top, rc.Width(), rc.Height(), hMemDC, 0, 0, width, height, merge);
-
- SelectBitmap(hMemDC, hbmOld);
- ::DeleteObject(hbmMem);
- ::DeleteDC(hMemDC);
+ 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 SurfaceImpl::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
- PenColour(fore);
- BrushColor(back);
- ::Ellipse(hdc, rc.left, rc.top, rc.right, rc.bottom);
+ 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 SurfaceImpl::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);
+ SurfaceImpl &surfOther = static_cast<SurfaceImpl &>(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();
+ }
}
// Buffer to hold strings and string position arrays without always allocating on heap.
@@ -792,109 +910,115 @@ public:
}
}
};
-typedef VarBuffer<int, stackBufferLength> TextPositions;
+typedef VarBuffer<XYPOSITION, stackBufferLength> TextPositions;
-void SurfaceImpl::DrawTextCommon(PRectangle rc, Font &font_, int ybase, const char *s, int len, UINT fuOptions) {
+void SurfaceImpl::DrawTextCommon(PRectangle rc, Font &font_, XYPOSITION ybase, const char *s, int len, UINT) {
SetFont(font_);
RECT rcw = RectFromPRectangle(rc);
- SIZE sz={0,0};
- int pos = 0;
- int x = rc.left;
-
- // Text drawing may fail if the text is too big.
- // If it does fail, slice up into segments and draw each segment.
- const int maxSegmentLength = 0x200;
-
- if ((!unicodeMode) && (IsNT() || (codePage==0) || win9xACPSame)) {
- // Use ANSI calls
- int lenDraw = Platform::Minimum(len, maxLenText);
- if (!::ExtTextOutA(hdc, x, ybase, fuOptions, &rcw, s, lenDraw, NULL)) {
- while (lenDraw > pos) {
- int seglen = Platform::Minimum(maxSegmentLength, lenDraw - pos);
- if (!::ExtTextOutA(hdc, x, ybase, fuOptions, &rcw, s+pos, seglen, NULL)) {
- PLATFORM_ASSERT(false);
- return;
- }
- ::GetTextExtentPoint32A(hdc, s+pos, seglen, &sz);
- x += sz.cx;
- pos += seglen;
- }
- }
- } else {
- // Use Unicode calls
- const TextWide tbuf(s, len, unicodeMode, codePage);
- if (!::ExtTextOutW(hdc, x, ybase, fuOptions, &rcw, tbuf.buffer, tbuf.tlen, NULL)) {
- while (tbuf.tlen > pos) {
- int seglen = Platform::Minimum(maxSegmentLength, tbuf.tlen - pos);
- if (!::ExtTextOutW(hdc, x, ybase, fuOptions, &rcw, tbuf.buffer+pos, seglen, NULL)) {
- PLATFORM_ASSERT(false);
- return;
- }
- ::GetTextExtentPoint32W(hdc, tbuf.buffer+pos, seglen, &sz);
- x += sz.cx;
- pos += seglen;
- }
+
+ // 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()+2, rc.Height(), &pTextLayout);
+ if (SUCCEEDED(hr)) {
+ D2D1_POINT_2F origin = {rc.left, ybase-baseline};
+ 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-baseline) / 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 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) {
- ::SetTextColor(hdc, fore.AsLong());
- ::SetBkColor(hdc, back.AsLong());
- DrawTextCommon(rc, font_, ybase, s, len, ETO_OPAQUE);
+ if (pRenderTarget) {
+ FillRectangle(rc, back);
+ D2DPenColour(fore);
+ DrawTextCommon(rc, font_, ybase, s, len, ETO_OPAQUE);
+ }
}
-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) {
- ::SetTextColor(hdc, fore.AsLong());
- ::SetBkColor(hdc, back.AsLong());
- DrawTextCommon(rc, font_, ybase, s, len, ETO_OPAQUE | ETO_CLIPPED);
+ if (pRenderTarget) {
+ FillRectangle(rc, back);
+ D2DPenColour(fore);
+ 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 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++) {
if (s[i] != ' ') {
- ::SetTextColor(hdc, fore.AsLong());
- ::SetBkMode(hdc, TRANSPARENT);
- DrawTextCommon(rc, font_, ybase, s, len, 0);
- ::SetBkMode(hdc, OPAQUE);
+ if (pRenderTarget) {
+ D2DPenColour(fore);
+ DrawTextCommon(rc, font_, ybase, s, len, 0);
+ }
return;
}
}
}
-int SurfaceImpl::WidthText(Font &font_, const char *s, int len) {
+XYPOSITION SurfaceImpl::WidthText(Font &font_, const char *s, int len) {
+ FLOAT width = 1.0;
SetFont(font_);
- SIZE sz={0,0};
- if ((!unicodeMode) && (IsNT() || (codePage==0) || win9xACPSame)) {
- ::GetTextExtentPoint32A(hdc, s, Platform::Minimum(len, maxLenText), &sz);
- } else {
- const TextWide tbuf(s, len, unicodeMode, codePage);
- ::GetTextExtentPoint32W(hdc, tbuf.buffer, tbuf.tlen, &sz);
+ 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 sz.cx;
+ return int(width + 0.5);
}
-void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positions) {
+void SurfaceImpl::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);
- 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
- // So measure the character widths by measuring each initial substring
- // Turns a linear operation into a qudratic but seems fast enough on test files
- for (int widthSS=0; widthSS < tbuf.tlen; widthSS++) {
- ::GetTextExtentPoint32W(hdc, tbuf.buffer, widthSS+1, &sz);
- poses.buffer[widthSS] = sz.cx;
+ 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);
@@ -921,39 +1045,17 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positi
while (i<len) {
positions[i++] = lastPos;
}
- } else if (IsNT() || (codePage==0) || win9xACPSame) {
- // Zero positions to avoid random behaviour on failure.
- memset(positions, 0, len * sizeof(*positions));
- // len may be larger than platform supports so loop over segments small enough for platform
- int startOffset = 0;
- while (len > 0) {
- int lenBlock = Platform::Minimum(len, maxLenText);
- if (!::GetTextExtentExPointA(hdc, s, lenBlock, maxWidthMeasure, &fit, positions, &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;
- }
- startOffset = positions[lenBlock-1];
- len -= lenBlock;
- positions += lenBlock;
- s += lenBlock;
+ } 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 {
- // Support Asian string display in 9x English
- const TextWide tbuf(s, len, unicodeMode, codePage);
- TextPositions poses(tbuf.tlen);
- for (int widthSS=0; widthSS<tbuf.tlen; widthSS++) {
- ::GetTextExtentPoint32W(hdc, tbuf.buffer, widthSS+1, &sz);
- poses.buffer[widthSS] = sz.cx;
- }
+ // May be more than one byte per position
int ui = 0;
for (int i=0;i<len;) {
if (::IsDBCSLeadByteEx(codePage, s[i])) {
@@ -970,77 +1072,138 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positi
}
}
-int SurfaceImpl::WidthChar(Font &font_, char ch) {
+XYPOSITION SurfaceImpl::WidthChar(Font &font_, char ch) {
+ FLOAT width = 1.0;
SetFont(font_);
- SIZE sz;
- ::GetTextExtentPoint32A(hdc, &ch, 1, &sz);
- return sz.cx;
+ 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);
}
-int SurfaceImpl::Ascent(Font &font_) {
+XYPOSITION SurfaceImpl::Ascent(Font &font_) {
+ FLOAT ascent = 1.0;
SetFont(font_);
- TEXTMETRIC tm;
- ::GetTextMetrics(hdc, &tm);
- return tm.tmAscent;
+ if (pIDWriteFactory && pTextFormat) {
+ SetFont(font_);
+ // Create a layout
+ IDWriteTextLayout *pTextLayout = 0;
+ HRESULT hr = pIDWriteFactory->CreateTextLayout(L"X", 1, pTextFormat, 1000.0, 1000.0, &pTextLayout);
+ if (SUCCEEDED(hr)) {
+ DWRITE_TEXT_METRICS textMetrics;
+ pTextLayout->GetMetrics(&textMetrics);
+ ascent = textMetrics.layoutHeight;
+ const int clusters = 20;
+ DWRITE_CLUSTER_METRICS clusterMetrics[clusters];
+ UINT32 count = 0;
+ pTextLayout->GetClusterMetrics(clusterMetrics, clusters, &count);
+ //height = pTextLayout->GetMaxHeight();
+ FLOAT minWidth = 0;
+ hr = pTextLayout->DetermineMinWidth(&minWidth);
+ const int maxLines = 2;
+ DWRITE_LINE_METRICS lineMetrics[maxLines];
+ UINT32 lineCount = 0;
+ hr = pTextLayout->GetLineMetrics(lineMetrics, maxLines, &lineCount);
+ if (SUCCEEDED(hr)) {
+ ascent = lineMetrics[0].baseline;
+ }
+ pTextLayout->Release();
+ }
+ }
+ return int(ascent + 0.5);
}
-int SurfaceImpl::Descent(Font &font_) {
+XYPOSITION SurfaceImpl::Descent(Font &font_) {
+ FLOAT descent = 1.0;
SetFont(font_);
- TEXTMETRIC tm;
- ::GetTextMetrics(hdc, &tm);
- return tm.tmDescent;
+ if (pIDWriteFactory && pTextFormat) {
+ // Create a layout
+ IDWriteTextLayout *pTextLayout = 0;
+ HRESULT hr = pIDWriteFactory->CreateTextLayout(L"X", 1, pTextFormat, 1000.0, 1000.0, &pTextLayout);
+ if (SUCCEEDED(hr)) {
+ const int maxLines = 2;
+ DWRITE_LINE_METRICS lineMetrics[maxLines];
+ UINT32 lineCount = 0;
+ hr = pTextLayout->GetLineMetrics(lineMetrics, maxLines, &lineCount);
+ if (SUCCEEDED(hr)) {
+ descent = lineMetrics[0].height - lineMetrics[0].baseline;
+ }
+ pTextLayout->Release();
+ }
+ }
+ return int(descent + 0.5);
}
-int SurfaceImpl::InternalLeading(Font &font_) {
- SetFont(font_);
- TEXTMETRIC tm;
- ::GetTextMetrics(hdc, &tm);
- return tm.tmInternalLeading;
+XYPOSITION SurfaceImpl::InternalLeading(Font &) {
+ return 0;
}
-int SurfaceImpl::ExternalLeading(Font &font_) {
- SetFont(font_);
- TEXTMETRIC tm;
- ::GetTextMetrics(hdc, &tm);
- return tm.tmExternalLeading;
+XYPOSITION SurfaceImpl::ExternalLeading(Font &) {
+ return 1;
}
-int SurfaceImpl::Height(Font &font_) {
+XYPOSITION SurfaceImpl::Height(Font &font_) {
+ FLOAT height = 1.0;
SetFont(font_);
- TEXTMETRIC tm;
- ::GetTextMetrics(hdc, &tm);
- return tm.tmHeight;
+ if (pIDWriteFactory && pTextFormat) {
+ // Create a layout
+ IDWriteTextLayout *pTextLayout = 0;
+ HRESULT hr = pIDWriteFactory->CreateTextLayout(L"X", 1, pTextFormat, 1000.0, 1000.0, &pTextLayout);
+ if (SUCCEEDED(hr)) {
+ const int maxLines = 2;
+ DWRITE_LINE_METRICS lineMetrics[maxLines];
+ UINT32 lineCount = 0;
+ hr = pTextLayout->GetLineMetrics(lineMetrics, maxLines, &lineCount);
+ if (SUCCEEDED(hr)) {
+ height = lineMetrics[0].height;
+ }
+ pTextLayout->Release();
+ }
+ }
+ // Truncating rather than rounding as otherwise too much space.
+ return int(height);
}
-int SurfaceImpl::AverageCharWidth(Font &font_) {
+XYPOSITION SurfaceImpl::AverageCharWidth(Font &font_) {
+ FLOAT width = 1.0;
SetFont(font_);
- TEXTMETRIC tm;
- ::GetTextMetrics(hdc, &tm);
- return tm.tmAveCharWidth;
+ 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 SurfaceImpl::SetPalette(Palette *pal, bool inBackGround) {
- if (paletteOld) {
- ::SelectPalette(hdc, paletteOld, TRUE);
- }
- paletteOld = 0;
- int changes = 0;
- if (pal->allowRealization) {
- paletteOld = ::SelectPalette(hdc,
- reinterpret_cast<HPALETTE>(pal->hpal), inBackGround);
- changes = ::RealizePalette(hdc);
- }
- return changes;
+int SurfaceImpl::SetPalette(Palette *, bool) {
+ return 0;
}
void SurfaceImpl::SetClip(PRectangle rc) {
- ::IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
+ if (pRenderTarget) {
+ D2D1_RECT_F rcClip = {rc.left, rc.top, rc.right, rc.bottom};
+ pRenderTarget->PushAxisAlignedClip(rcClip, D2D1_ANTIALIAS_MODE_ALIASED);
+ clipsActive++;
+ }
}
void SurfaceImpl::FlushCachedState() {
- pen = 0;
- brush = 0;
- font = 0;
}
void SurfaceImpl::SetUnicodeMode(bool unicodeMode_) {
@@ -1651,6 +1814,8 @@ void ListBoxX::Draw(DRAWITEMSTRUCT *pDrawItem) {
if (pimage) {
Surface *surfaceItem = Surface::Allocate();
if (surfaceItem) {
+ // TODO: Need a DC RenderTarget here
+ /*
surfaceItem->Init(pDrawItem->hDC, pDrawItem->hwndItem);
int left = pDrawItem->rcItem.left + ItemInset.x + ImageInset.x;
PRectangle rcImage(left, pDrawItem->rcItem.top,
@@ -1658,6 +1823,7 @@ void ListBoxX::Draw(DRAWITEMSTRUCT *pDrawItem) {
surfaceItem->DrawRGBAImage(rcImage,
pimage->GetWidth(), pimage->GetHeight(), pimage->Pixels());
delete surfaceItem;
+ */
::SetTextAlign(pDrawItem->hDC, TA_TOP);
}
}
diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx
index 9925a64bb..28e48596b 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"
@@ -197,6 +200,10 @@ class ScintillaWin :
static HINSTANCE hInstance;
+ IDWriteFactory *pIDWriteFactory;
+ ID2D1Factory *pD2DFactory;
+ ID2D1HwndRenderTarget *pRenderTarget;
+
ScintillaWin(HWND hwnd);
ScintillaWin(const ScintillaWin &);
virtual ~ScintillaWin();
@@ -204,6 +211,8 @@ class ScintillaWin :
virtual void Initialise();
virtual void Finalise();
+ void EnsureRenderTarget();
+ void DropRenderTarget();
HWND MainHWND();
static sptr_t DirectFunction(
@@ -350,6 +359,10 @@ ScintillaWin::ScintillaWin(HWND hwnd) {
sysCaretWidth = 0;
sysCaretHeight = 0;
+ pIDWriteFactory = 0;
+ pD2DFactory = 0;
+ pRenderTarget = 0;
+
keysAlwaysUnicode = false;
caret.period = ::GetCaretBlinkTime();
@@ -378,18 +391,69 @@ void ScintillaWin::Initialise() {
::GetProcAddress(commctrl32, "_TrackMouseEvent");
}
}
+
+ if (!pIDWriteFactory) {
+ DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
+ __uuidof(IDWriteFactory),
+ reinterpret_cast<IUnknown**>(&pIDWriteFactory));
+ }
+ if (!pD2DFactory) {
+ D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory);
+ }
}
void ScintillaWin::Finalise() {
ScintillaBase::Finalise();
SetTicking(false);
SetIdle(false);
+ DropRenderTarget();
+ if (pIDWriteFactory) {
+ pIDWriteFactory->Release();
+ pIDWriteFactory = 0;
+ }
+ if (pD2DFactory) {
+ pD2DFactory->Release();
+ pD2DFactory = 0;
+ }
::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,8 +569,11 @@ LRESULT ScintillaWin::WndPaint(uptr_t wParam) {
pps = &ps;
::BeginPaint(MainHWND(), pps);
}
- AutoSurface surfaceWindow(pps->hdc, this);
+ //AutoSurface surfaceWindow(pps->hdc, this);
+ 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);
@@ -517,6 +584,10 @@ LRESULT ScintillaWin::WndPaint(uptr_t wParam) {
}
Paint(surfaceWindow, rcPaint);
surfaceWindow->Release();
+ HRESULT hr = pRenderTarget->EndDraw();
+ if (hr == D2DERR_RECREATE_TARGET) {
+ DropRenderTarget();
+ }
}
if (hRgnUpdate) {
::DeleteRgn(hRgnUpdate);
@@ -674,6 +745,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();
}
@@ -1189,11 +1261,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() {
@@ -2283,7 +2356,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
@@ -2296,6 +2371,7 @@ void ScintillaWin::RealizeWindowPalette(bool inBackGround) {
surfaceWindow->Release();
}
::ReleaseDC(MainHWND(), hdc);
+*/
}
/**
@@ -2303,23 +2379,30 @@ void ScintillaWin::RealizeWindowPalette(bool inBackGround) {
* This paint will not be abandoned.
*/
void ScintillaWin::FullPaint() {
- HDC hdc = ::GetDC(MainHWND());
- FullPaintDC(hdc);
- ::ReleaseDC(MainHWND(), hdc);
+ //HDC hdc = ::GetDC(MainHWND());
+ //FullPaintDC(hdc);
+ //::ReleaseDC(MainHWND(), hdc);
+ FullPaintDC(0);
}
/**
* Redraw all of text area on the specified DC.
* This paint will not be abandoned.
*/
-void ScintillaWin::FullPaintDC(HDC hdc) {
+void ScintillaWin::FullPaintDC(HDC) {
paintState = painting;
rcPaint = GetClientRectangle();
paintingAllText = true;
- AutoSurface surfaceWindow(hdc, this);
+ 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;
}
@@ -2693,10 +2776,21 @@ sptr_t PASCAL ScintillaWin::CTWndProc(
::BeginPaint(hWnd, &ps);
Surface *surfaceWindow = Surface::Allocate();
if (surfaceWindow) {
- surfaceWindow->Init(ps.hdc, hWnd);
+ ID2D1HwndRenderTarget *pCTRenderTarget = 0;
+ RECT rc;
+ GetClientRect(hWnd, &rc);
+ // Create a Direct2D render target.
+ sciThis->pD2DFactory->CreateHwndRenderTarget(
+ D2D1::RenderTargetProperties(),
+ D2D1::HwndRenderTargetProperties(hWnd, D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)),
+ &pCTRenderTarget);
+ //surfaceWindow->Init(ps.hdc, hWnd);
+ surfaceWindow->Init(pCTRenderTarget, hWnd);
surfaceWindow->SetUnicodeMode(SC_CP_UTF8 == sciThis->ct.codePage);
surfaceWindow->SetDBCSMode(sciThis->ct.codePage);
+ pCTRenderTarget->BeginDraw();
sciThis->ct.PaintCT(surfaceWindow);
+ pCTRenderTarget->EndDraw();
surfaceWindow->Release();
delete surfaceWindow;
}