public HRESULT GetCurrentFontFile(out IDWriteFontFile fontFile)
            {
                DWriteFontFile file;

                try
                {
                    file = _enumerator.Current;
                }
                catch (Exception e)
                {
                    ComError.SetError(e.GetAllMessages());
                    fontFile = null;
                    return(HRESULTS.DISP_E_EXCEPTION);
                }

                if (file is DWriteFontStreamFile sf && sf.FilePath != null)
                {
                    using (var mem = new ComMemory(Marshal.SizeOf <long>()))
                    {
                        if (sf.LastWriteTime.HasValue)
                        {
                            Marshal.WriteInt64(mem.Pointer, sf.LastWriteTime.Value.ToFileTime());
                        }

                        var ptr = sf.LastWriteTime.HasValue ? mem.Pointer : IntPtr.Zero;
                        return(_factory.CreateFontFileReference(sf.FilePath, ptr, out fontFile));
                    }
                }

                var stream = new FontFileStream(file);

                _loader.AddStream(stream);
                return(_factory.CreateCustomFontFileReference(stream.Key, (uint)stream.KeySize, _loader, out fontFile));
            }
Esempio n. 2
0
        unsafe internal static IDWriteFontFile CreateFontFile(
            IDWriteFactory factory,
            IntPtr fontFileLoader,                                                // IDWriteFontFileLoader*
            Uri filePathUri
            )
        {
            IDWriteFontFile dwriteFontFile;
            bool            isLocal = Factory.IsLocalUri(filePathUri);

            if (isLocal)
            {
                // DWrite currently has a slow lookup for the last write time, which
                // introduced a noticable perf regression when we switched over.
                // To mitigate this scenario, we will fetch the timestamp ourselves
                // and cache it for future calls.
                //
                // Note: we only do this if a Dispatcher exists for the current
                // thread.  There is a seperate cache for each thread.
                FILETIME   cachedTimeStamp;
                IntPtr     pTimeStamp        = IntPtr.Zero;      // If something fails, do nothing and let DWrite sort it out.
                Dispatcher currentDispatcher = Dispatcher.FromThread(Thread.CurrentThread);
                if (currentDispatcher != null)
                {
                    try {
                        // One-time initialization per thread.
                        if (_timeStampCache == null)
                        {
                            _timeStampCache = new Dictionary <Uri, FILETIME>();
                        }

                        if (!_timeStampCache.TryGetValue(filePathUri, out cachedTimeStamp))
                        {
                            long longFileTime = File.GetLastWriteTime(filePathUri.LocalPath).ToFileTime();
                            cachedTimeStamp.dwLowDateTime  = (int)(longFileTime);
                            cachedTimeStamp.dwHighDateTime = (int)(longFileTime >> 32);
                            _timeStampCache.Add(filePathUri, cachedTimeStamp);

                            // We don't want to hold this cached value for a long time since
                            // all font references will be tied to this timestamp, and any font
                            // update during the lifetime of the application will cause is to
                            // encounter errors.  So we use a dispatcher operation to clear
                            // the cache as soon as we get back to pumping messages.
                            if (_timeStampCacheCleanupOp == null)
                            {
                                _timeStampCacheCleanupOp = currentDispatcher.BeginInvoke(new Action(CleanupTimeStampCache));
                            }
                        }

                        pTimeStamp = Marshal.AllocCoTaskMem(Marshal.SizeOf <FILETIME>());
                        Marshal.StructureToPtr <FILETIME>(cachedTimeStamp, pTimeStamp, false);
                    }
                    catch { }
                }

                try {
                    dwriteFontFile = factory.CreateFontFileReference(
                        filePathUri.LocalPath,
                        pTimeStamp
                        );
                }
                finally {
                    Marshal.FreeCoTaskMem(pTimeStamp);
                }
            }
            else
            {
                string filePath = filePathUri.AbsoluteUri;

                fixed(char *pFilePath = filePath)
                {
                    dwriteFontFile = factory.CreateCustomFontFileReference(
                        new IntPtr(pFilePath),
                        (uint)(filePath.Length + 1) * 2,
                        fontFileLoader
                        );
                }
            }
            return(dwriteFontFile);
        }