// This idea was borrowed from Google Chrome's uniscribe handler: // https://code.google.com/p/chromium/codesearch#chromium/src/ui/gfx/font_fallback_win.cc&q=uniscribe&sq=package:chromium&l=283&dr=CSs // also as discussed here: // http://stackoverflow.com/questions/16828868/how-to-automatically-choose-most-suitable-font-for-different-language private static bool GetUniscribeFallbackFont( Font font, IntPtr text, int textLength, out GDI.LOGFONT fallbackFont) { fallbackFont = new GDI.LOGFONT(); // Figure out what font Uniscribe chooses for fallback by making it write to a // metafile and then cracking it open. using (GDIDC hdc = GDIDC.CreateCompatibleDC(IntPtr.Zero)) { IntPtr hdcMF_ = GDI.CreateEnhMetaFile(hdc, null, IntPtr.Zero, null); if (hdcMF_ == IntPtr.Zero) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } using (GDIDC hdcMF = new GDIDC(hdcMF_)) { using (GDIFont gdiFont = new GDIFont(font)) { GDI.SelectObject(hdcMF, gdiFont); IntPtr sa = IntPtr.Zero; try { int hr; hr = ScriptStringAnalyse( hdcMF, text, textLength, 0, // cGlyphs -1, // iCharSet SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK, 0, // required width IntPtr.Zero, // SCRIPT_CONTROL IntPtr.Zero, // SCRIPT_STATE null, // piDx IntPtr.Zero, // SCRIPT_TABDEF null, // legacy out sa); if (hr < 0) { return false; } hr = ScriptStringOut( sa, 0, // iX 0, // iY 0, // ExtTextOut options IntPtr.Zero, // rect 0, // iMinSel 0, // iMaxSel false); // fDisabled if (hr < 0) { return false; } } finally { ScriptStringFree(ref sa); } IntPtr hMF = GDI.CloseEnhMetaFile(hdcMF); if (hMF == IntPtr.Zero) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } try { GDI.LOGFONT lf = new GDI.LOGFONT(); bool r = GDI.EnumEnhMetaFile( IntPtr.Zero, // hdc hMF, delegate ( IntPtr hdc_, IntPtr[] lpht,// capacity is nHandles IntPtr lpmr, // ENHMETARECORD int nHandles, int data) // LPARAM { // read lpmr->iType int iType = Marshal.ReadInt32(lpmr); if (iType == GDI.EMR_EXTCREATEFONTINDIRECTW) { object cfio = Marshal.PtrToStructure(lpmr, typeof(GDI.EMREXTCREATEFONTINDIRECT)); GDI.EMREXTCREATEFONTINDIRECT cfi = (GDI.EMREXTCREATEFONTINDIRECT)cfio; // Last one wins! lf = cfi.elfw.elfLogFont; } return 1; }, IntPtr.Zero, // LPARAM IntPtr.Zero); // &RECT if (!r) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } if (!String.IsNullOrEmpty(lf.lfFaceName)) { fallbackFont = lf; return true; } } finally { GDI.DeleteEnhMetaFile(hMF); } return false; } } } }
public void Reset( Font font, int visibleWidth) { ClearCaches(); if (hdcOffscreenStrip != null) { hdcOffscreenStrip.Dispose(); hdcOffscreenStrip = null; } if (offscreenStrip != null) { offscreenStrip.Dispose(); offscreenStrip = null; } this.visibleWidth = visibleWidth; // allocation of offscreenStrip is deferred until HDC is available to make compatible with this.font = font; }
public void Dispose() { ClearCaches(); if (hdcOffscreenStrip != null) { hdcOffscreenStrip.Dispose(); hdcOffscreenStrip = null; } if (offscreenStrip != null) { offscreenStrip.Dispose(); offscreenStrip = null; } GC.SuppressFinalize(this); }
public ITextInfo AnalyzeText( Graphics graphics, Font font, int fontHeight, string line) { int index; if ((index = line.IndexOfAny(new char[] { '\r', '\n' })) >= 0) { Debug.Assert(false); throw new ArgumentException(); } if (offscreenStrip == null) { using (GraphicsHDC hdc = new GraphicsHDC(graphics)) { offscreenStrip = new GDIBitmap(visibleWidth, fontHeight, hdc); } Debug.Assert(hdcOffscreenStrip == null); hdcOffscreenStrip = GDIDC.Create(offscreenStrip); } using (Pin<string> pinLine = new Pin<string>(line)) { return TextItems.AnalyzeText( this, hdcOffscreenStrip, pinLine.AddrOfPinnedObject(), new FontRunInfo[] { new FontRunInfo(line.Length, font, fontHeight) }); } }
public GDIOffscreenBitmap(Graphics graphicsCompatibleWith, int width, int height) { if ((width <= 0) || (height <= 0)) { Debug.Assert(false); throw new ArgumentException(); } // Create GDI objects for offscreen. Must be created through GDI because Uniscribe/DirectWrite do not // like objects created by GDI+ and will draw with very poor quality on them. using (GraphicsHDC hDC = new GraphicsHDC(graphicsCompatibleWith)) { this.hDC = GDIDC.CreateCompatibleDC(hDC); hBitmap = new GDIBitmap(width, height, PixelFormat.Format32bppArgb); GDI.SelectObject(this.hDC, hBitmap); } graphics = Graphics.FromHdc(hDC); }
public static GDIDC Create(GDIBitmap bitmap) { IntPtr hdc = GDI.CreateCompatibleDC(IntPtr.Zero); if (hdc == IntPtr.Zero) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } GDIDC gdidc = new GDIDC(hdc); GDI.SelectObject(hdc, bitmap); return gdidc; }