// 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) });
            }
        }
Example #5
0
        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);
        }
Example #6
0
 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;
 }