mirror of
https://github.com/QL-Win/QuickLook.git
synced 2025-09-12 10:19:07 +00:00
Go back from Webkit to IE render engine
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
50
QuickLook.Plugin/QuickLook.Plugin.HtmlViewer/Helper.cs
Normal file
50
QuickLook.Plugin/QuickLook.Plugin.HtmlViewer/Helper.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace QuickLook.Plugin.HtmlViewer
|
||||
{
|
||||
internal static class Helper
|
||||
{
|
||||
public static string FilePathToFileUrl(string filePath)
|
||||
{
|
||||
var uri = new StringBuilder();
|
||||
foreach (var v in filePath)
|
||||
if (v >= 'a' && v <= 'z' || v >= 'A' && v <= 'Z' || v >= '0' && v <= '9' ||
|
||||
v == '+' || v == '/' || v == ':' || v == '.' || v == '-' || v == '_' || v == '~' ||
|
||||
v > '\xFF')
|
||||
uri.Append(v);
|
||||
else if (v == Path.DirectorySeparatorChar || v == Path.AltDirectorySeparatorChar)
|
||||
uri.Append('/');
|
||||
else
|
||||
uri.Append($"%{(int) v:X2}");
|
||||
if (uri.Length >= 2 && uri[0] == '/' && uri[1] == '/') // UNC path
|
||||
uri.Insert(0, "file:");
|
||||
else
|
||||
uri.Insert(0, "file:///");
|
||||
return uri.ToString();
|
||||
}
|
||||
|
||||
public static void SetBrowserFeatureControl()
|
||||
{
|
||||
var exeName = Path.GetFileName(App.AppFullPath);
|
||||
|
||||
// use latest engine
|
||||
SetBrowserFeatureControlKey("FEATURE_BROWSER_EMULATION", exeName, 0);
|
||||
//
|
||||
SetBrowserFeatureControlKey("FEATURE_GPU_RENDERING", exeName, 0);
|
||||
// turn on hi-dpi mode
|
||||
SetBrowserFeatureControlKey("FEATURE_96DPI_PIXEL", exeName, 1);
|
||||
}
|
||||
|
||||
private static void SetBrowserFeatureControlKey(string feature, string appName, uint value)
|
||||
{
|
||||
using (var key = Registry.CurrentUser.CreateSubKey(
|
||||
string.Concat(@"Software\Microsoft\Internet Explorer\Main\FeatureControl\", feature),
|
||||
RegistryKeyPermissionCheck.ReadWriteSubTree))
|
||||
{
|
||||
key?.SetValue(appName, value, RegistryValueKind.DWord);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,36 +0,0 @@
|
||||
// Copyright © 2010-2017 The CefSharp Authors. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
using CefSharp;
|
||||
|
||||
namespace QuickLook.Plugin.HtmlViewer
|
||||
{
|
||||
public class JsDialogHandler : IJsDialogHandler
|
||||
{
|
||||
public bool OnJSDialog(IWebBrowser browserControl, IBrowser browser, string originUrl,
|
||||
CefJsDialogType dialogType, string messageText, string defaultPromptText, IJsDialogCallback callback,
|
||||
ref bool suppressMessage)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool OnJSBeforeUnload(IWebBrowser browserControl, IBrowser browser, string message, bool isReload,
|
||||
IJsDialogCallback callback)
|
||||
{
|
||||
//NOTE: No need to execute the callback if you return false
|
||||
// callback.Continue(true);
|
||||
|
||||
//NOTE: Returning false will trigger the default behaviour, you need to return true to handle yourself.
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnResetDialogState(IWebBrowser browserControl, IBrowser browser)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnDialogClosed(IWebBrowser browserControl, IBrowser browser)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,35 +0,0 @@
|
||||
// Copyright © 2010-2017 The CefSharp Authors. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
using CefSharp;
|
||||
|
||||
namespace QuickLook.Plugin.HtmlViewer
|
||||
{
|
||||
internal class MenuHandler : IContextMenuHandler
|
||||
{
|
||||
public void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame,
|
||||
IContextMenuParams parameters,
|
||||
IMenuModel model)
|
||||
{
|
||||
}
|
||||
|
||||
public bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame,
|
||||
IContextMenuParams parameters,
|
||||
CefMenuCommand commandId, CefEventFlags eventFlags)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame)
|
||||
{
|
||||
}
|
||||
|
||||
public bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame,
|
||||
IContextMenuParams parameters,
|
||||
IMenuModel model, IRunContextMenuCallback callback)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,15 +1,16 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace QuickLook.Plugin.HtmlViewer
|
||||
{
|
||||
public class Plugin : IViewer
|
||||
{
|
||||
private WebkitPanel _panel;
|
||||
private WebpagePanel _panel;
|
||||
|
||||
public int Priority => int.MaxValue;
|
||||
public bool AllowsTransparency => true;
|
||||
public bool AllowsTransparency => false;
|
||||
|
||||
public bool CanHandle(string path)
|
||||
{
|
||||
@@ -36,12 +37,12 @@ namespace QuickLook.Plugin.HtmlViewer
|
||||
|
||||
public void View(string path, ContextObject context)
|
||||
{
|
||||
_panel = new WebkitPanel();
|
||||
_panel = new WebpagePanel();
|
||||
context.ViewerContent = _panel;
|
||||
context.Title = Path.IsPathRooted(path) ? Path.GetFileName(path) : path;
|
||||
|
||||
_panel.Navigate(path);
|
||||
context.IsBusy = false;
|
||||
_panel.Dispatcher.Invoke(() => { context.IsBusy = false; }, DispatcherPriority.Loaded);
|
||||
}
|
||||
|
||||
public void Cleanup()
|
||||
|
@@ -35,20 +35,10 @@
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="CefSharp, Version=57.0.0.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=x86">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>References\CefSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="CefSharp.Core, Version=57.0.0.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=x86">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>References\CefSharp.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="CefSharp.Wpf, Version=57.0.0.0, Culture=neutral, PublicKeyToken=40c4b6fc221f4138, processorArchitecture=x86">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>References\CefSharp.Wpf.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xaml">
|
||||
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||
</Reference>
|
||||
@@ -57,20 +47,18 @@
|
||||
<Reference Include="PresentationFramework" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Include="WebkitPanel.xaml">
|
||||
<Compile Include="WpfBrowserWrapper.cs" />
|
||||
<Page Include="WebpagePanel.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="..\..\GitVersion.cs">
|
||||
<Link>Properties\GitVersion.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="JsDialogHandler.cs" />
|
||||
<Compile Include="MenuHandler.cs" />
|
||||
<Compile Include="Plugin.cs" />
|
||||
<Compile Include="RequestHandler.cs" />
|
||||
<Compile Include="UrlHelper.cs" />
|
||||
<Compile Include="WebkitPanel.xaml.cs">
|
||||
<DependentUpon>WebkitPanel.xaml</DependentUpon>
|
||||
<Compile Include="Helper.cs" />
|
||||
<Compile Include="WebpagePanel.xaml.cs">
|
||||
<DependentUpon>WebpagePanel.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
@@ -78,38 +66,6 @@
|
||||
<Compile Include="Properties\AssemblyInfo.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<ContentWithTargetPath Include="CefSharp\cef.pak">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>cef.pak</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="CefSharp\cef_100_percent.pak">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>cef_100_percent.pak</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="CefSharp\cef_200_percent.pak">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>cef_200_percent.pak</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="CefSharp\cef_extensions.pak">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>cef_extensions.pak</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="CefSharp\icudtl.dat">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>icudtl.dat</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="CefSharp\locales\en-US.pak">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>locales\en-US.pak</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="CefSharp\natives_blob.bin">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>natives_blob.bin</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="CefSharp\snapshot_blob.bin">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>snapshot_blob.bin</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\QuickLook\QuickLook.csproj">
|
||||
@@ -119,38 +75,15 @@
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ContentWithTargetPath Include="CefSharp\CefSharp.BrowserSubprocess.Core.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>CefSharp.BrowserSubprocess.Core.dll</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="CefSharp\CefSharp.BrowserSubprocess.exe">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>CefSharp.BrowserSubprocess.exe</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="CefSharp\chrome_elf.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>chrome_elf.dll</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="CefSharp\d3dcompiler_47.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>d3dcompiler_47.dll</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="CefSharp\libcef.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>libcef.dll</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="CefSharp\libEGL.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>libEGL.dll</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="CefSharp\libGLESv2.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>libGLESv2.dll</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<ContentWithTargetPath Include="CefSharp\widevinecdmadapter.dll">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<TargetPath>widevinecdmadapter.dll</TargetPath>
|
||||
</ContentWithTargetPath>
|
||||
<COMReference Include="SHDocVw">
|
||||
<Guid>{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}</Guid>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>1</VersionMinor>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<Isolated>False</Isolated>
|
||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
@@ -1,113 +0,0 @@
|
||||
// Copyright © 2010-2017 The CefSharp Authors. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using CefSharp;
|
||||
|
||||
namespace QuickLook.Plugin.HtmlViewer
|
||||
{
|
||||
public class RequestHandler : IRequestHandler
|
||||
{
|
||||
bool IRequestHandler.OnBeforeBrowse(IWebBrowser browserControl, IBrowser browser, IFrame frame,
|
||||
IRequest request, bool isRedirect)
|
||||
{
|
||||
return request.TransitionType != TransitionType.Explicit;
|
||||
}
|
||||
|
||||
bool IRequestHandler.OnOpenUrlFromTab(IWebBrowser browserControl, IBrowser browser, IFrame frame,
|
||||
string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture)
|
||||
{
|
||||
return OnOpenUrlFromTab(browserControl, browser, frame, targetUrl, targetDisposition, userGesture);
|
||||
}
|
||||
|
||||
bool IRequestHandler.OnCertificateError(IWebBrowser browserControl, IBrowser browser, CefErrorCode errorCode,
|
||||
string requestUrl, ISslInfo sslInfo, IRequestCallback callback)
|
||||
{
|
||||
callback.Dispose();
|
||||
return false;
|
||||
}
|
||||
|
||||
void IRequestHandler.OnPluginCrashed(IWebBrowser browserControl, IBrowser browser, string pluginPath)
|
||||
{
|
||||
}
|
||||
|
||||
CefReturnValue IRequestHandler.OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame,
|
||||
IRequest request, IRequestCallback callback)
|
||||
{
|
||||
return CefReturnValue.Continue;
|
||||
}
|
||||
|
||||
bool IRequestHandler.GetAuthCredentials(IWebBrowser browserControl, IBrowser browser, IFrame frame,
|
||||
bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback)
|
||||
{
|
||||
callback.Dispose();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IRequestHandler.OnSelectClientCertificate(IWebBrowser browserControl, IBrowser browser, bool isProxy,
|
||||
string host, int port, X509Certificate2Collection certificates, ISelectClientCertificateCallback callback)
|
||||
{
|
||||
//NOTE: If you do not wish to implement this method returning false is the default behaviour
|
||||
// We also suggest you explicitly Dispose of the callback as it wraps an unmanaged resource.
|
||||
|
||||
return OnSelectClientCertificate(browserControl, browser, isProxy, host, port, certificates, callback);
|
||||
}
|
||||
|
||||
void IRequestHandler.OnRenderProcessTerminated(IWebBrowser browserControl, IBrowser browser,
|
||||
CefTerminationStatus status)
|
||||
{
|
||||
}
|
||||
|
||||
bool IRequestHandler.OnQuotaRequest(IWebBrowser browserControl, IBrowser browser, string originUrl,
|
||||
long newSize, IRequestCallback callback)
|
||||
{
|
||||
callback.Dispose();
|
||||
return false;
|
||||
}
|
||||
|
||||
void IRequestHandler.OnResourceRedirect(IWebBrowser browserControl, IBrowser browser, IFrame frame,
|
||||
IRequest request, IResponse response, ref string newUrl)
|
||||
{
|
||||
}
|
||||
|
||||
bool IRequestHandler.OnProtocolExecution(IWebBrowser browserControl, IBrowser browser, string url)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void IRequestHandler.OnRenderViewReady(IWebBrowser browserControl, IBrowser browser)
|
||||
{
|
||||
}
|
||||
|
||||
bool IRequestHandler.OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame,
|
||||
IRequest request, IResponse response)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IResponseFilter IRequestHandler.GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser,
|
||||
IFrame frame, IRequest request, IResponse response)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
void IRequestHandler.OnResourceLoadComplete(IWebBrowser browserControl, IBrowser browser, IFrame frame,
|
||||
IRequest request, IResponse response, UrlRequestStatus status, long receivedContentLength)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual bool OnOpenUrlFromTab(IWebBrowser browserControl, IBrowser browser, IFrame frame,
|
||||
string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected virtual bool OnSelectClientCertificate(IWebBrowser browserControl, IBrowser browser, bool isProxy,
|
||||
string host, int port, X509Certificate2Collection certificates, ISelectClientCertificateCallback callback)
|
||||
{
|
||||
callback.Dispose();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,27 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace QuickLook.Plugin.HtmlViewer
|
||||
{
|
||||
internal static class UrlHelper
|
||||
{
|
||||
internal static string FilePathToFileUrl(string filePath)
|
||||
{
|
||||
var uri = new StringBuilder();
|
||||
foreach (var v in filePath)
|
||||
if (v >= 'a' && v <= 'z' || v >= 'A' && v <= 'Z' || v >= '0' && v <= '9' ||
|
||||
v == '+' || v == '/' || v == ':' || v == '.' || v == '-' || v == '_' || v == '~' ||
|
||||
v > '\xFF')
|
||||
uri.Append(v);
|
||||
else if (v == Path.DirectorySeparatorChar || v == Path.AltDirectorySeparatorChar)
|
||||
uri.Append('/');
|
||||
else
|
||||
uri.Append($"%{(int) v:X2}");
|
||||
if (uri.Length >= 2 && uri[0] == '/' && uri[1] == '/') // UNC path
|
||||
uri.Insert(0, "file:");
|
||||
else
|
||||
uri.Insert(0, "file:///");
|
||||
return uri.ToString();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,63 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using CefSharp;
|
||||
|
||||
namespace QuickLook.Plugin.HtmlViewer
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for UserControl1.xaml
|
||||
/// </summary>
|
||||
public partial class WebkitPanel : UserControl, IDisposable
|
||||
{
|
||||
private readonly string _cefPath =
|
||||
Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
|
||||
|
||||
public WebkitPanel()
|
||||
{
|
||||
var libraryLoader = new CefLibraryHandle(Path.Combine(_cefPath, "libcef.dll"));
|
||||
|
||||
if (!Cef.IsInitialized)
|
||||
Cef.Initialize(new CefSettings
|
||||
{
|
||||
BrowserSubprocessPath = Path.Combine(_cefPath, "CefSharp.BrowserSubprocess.exe"),
|
||||
LocalesDirPath = Path.Combine(_cefPath, "locales"),
|
||||
ResourcesDirPath = _cefPath,
|
||||
LogSeverity = LogSeverity.Disable,
|
||||
CefCommandLineArgs = {new KeyValuePair<string, string>("disable-gpu", "1")}
|
||||
});
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
Application.Current.Exit += (sender, e) => Cef.Shutdown();
|
||||
|
||||
browser.RequestHandler = new RequestHandler();
|
||||
browser.MenuHandler = new MenuHandler();
|
||||
browser.JsDialogHandler = new JsDialogHandler();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
browser?.Dispose();
|
||||
}
|
||||
|
||||
public void Navigate(string path)
|
||||
{
|
||||
if (Path.IsPathRooted(path))
|
||||
path = UrlHelper.FilePathToFileUrl(path);
|
||||
|
||||
browser.IsBrowserInitializedChanged += (sender, e) => browser.Load(path);
|
||||
}
|
||||
|
||||
public void LoadHtml(string html, string path)
|
||||
{
|
||||
if (Path.IsPathRooted(path))
|
||||
path = UrlHelper.FilePathToFileUrl(path);
|
||||
|
||||
browser.IsBrowserInitializedChanged += (sender, e) => browser.LoadHtml(html, path);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,13 +1,12 @@
|
||||
<UserControl x:Class="QuickLook.Plugin.HtmlViewer.WebkitPanel"
|
||||
<UserControl x:Class="QuickLook.Plugin.HtmlViewer.WebpagePanel"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:QuickLook.Plugin.HtmlViewer"
|
||||
xmlns:cef="clr-namespace:CefSharp.Wpf;assembly=CefSharp.Wpf"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="300">
|
||||
<Grid>
|
||||
<cef:ChromiumWebBrowser x:Name="browser" />
|
||||
<local:WpfWebBrowserWrapper x:Name="browser" Zoom="200" />
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace QuickLook.Plugin.HtmlViewer
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for UserControl1.xaml
|
||||
/// </summary>
|
||||
public partial class WebpagePanel : UserControl, IDisposable
|
||||
{
|
||||
public WebpagePanel()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Helper.SetBrowserFeatureControl();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
browser?.Dispose();
|
||||
browser = null;
|
||||
}
|
||||
|
||||
public void Navigate(string path)
|
||||
{
|
||||
if (Path.IsPathRooted(path))
|
||||
path = Helper.FilePathToFileUrl(path);
|
||||
|
||||
browser.Dispatcher.Invoke(() => { browser.Navigate(path); }, DispatcherPriority.Loaded);
|
||||
}
|
||||
|
||||
public void LoadHtml(string html)
|
||||
{
|
||||
var s = new MemoryStream(Encoding.UTF8.GetBytes(html ?? ""));
|
||||
|
||||
browser.Dispatcher.Invoke(() => { browser.Navigate(s); }, DispatcherPriority.Loaded);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,230 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Navigation;
|
||||
using SHDocVw;
|
||||
using HorizontalAlignment = System.Windows.HorizontalAlignment;
|
||||
using WebBrowser = System.Windows.Controls.WebBrowser;
|
||||
|
||||
namespace QuickLook.Plugin.HtmlViewer
|
||||
{
|
||||
/// <summary>
|
||||
/// Class wraps a Browser (which itself is a bad designed WPF control) and presents itself as
|
||||
/// a better designed WPF control. For example provides a bindable source property or commands.
|
||||
/// </summary>
|
||||
public class WpfWebBrowserWrapper : ContentControl, IDisposable
|
||||
{
|
||||
private static readonly Guid SidSWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");
|
||||
|
||||
private WebBrowser _innerBrowser;
|
||||
private bool _loaded;
|
||||
private int _zoom;
|
||||
|
||||
public WpfWebBrowserWrapper()
|
||||
{
|
||||
_innerBrowser = new WebBrowser
|
||||
{
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
VerticalAlignment = VerticalAlignment.Stretch
|
||||
};
|
||||
|
||||
Content = _innerBrowser;
|
||||
_innerBrowser.Navigated += InnerBrowserNavigated;
|
||||
_innerBrowser.Navigating += InnerBrowserNavigating;
|
||||
_innerBrowser.LoadCompleted += InnerBrowserLoadCompleted;
|
||||
_innerBrowser.Loaded += InnerBrowserLoaded;
|
||||
_innerBrowser.SizeChanged += InnerBrowserSizeChanged;
|
||||
}
|
||||
|
||||
public string Url { get; private set; }
|
||||
|
||||
public int Zoom
|
||||
{
|
||||
get => _zoom;
|
||||
set
|
||||
{
|
||||
_zoom = value;
|
||||
ApplyZoom();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// gets the browser control's underlying activeXcontrol. Ready only from within Loaded-event but before loaded Document!
|
||||
// do not use prior loaded event.
|
||||
public InternetExplorer ActiveXControl
|
||||
{
|
||||
get
|
||||
{
|
||||
// this is a brilliant way to access the WebBrowserObject prior to displaying the actual document (eg. Document property)
|
||||
var fiComWebBrowser =
|
||||
typeof(WebBrowser).GetField("_axIWebBrowser2", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
if (fiComWebBrowser == null) return null;
|
||||
var objComWebBrowser = fiComWebBrowser.GetValue(_innerBrowser);
|
||||
return objComWebBrowser as InternetExplorer;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_innerBrowser.Source = null;
|
||||
_innerBrowser.Dispose();
|
||||
_innerBrowser = null;
|
||||
Content = null;
|
||||
}
|
||||
|
||||
private void InnerBrowserSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
ApplyZoom();
|
||||
}
|
||||
|
||||
private void InnerBrowserLoaded(object sender, EventArgs e)
|
||||
{
|
||||
// make browser control not silent: allow HTTP-Auth-dialogs. Requery command availability
|
||||
var ie = ActiveXControl;
|
||||
ie.Silent = true;
|
||||
}
|
||||
|
||||
// called when the loading of a web page is done
|
||||
private void InnerBrowserLoadCompleted(object sender, NavigationEventArgs e)
|
||||
{
|
||||
ApplyZoom(); // apply later and not only at changed event, since only works if browser is rendered.
|
||||
}
|
||||
|
||||
// called when the browser started to load and retrieve data.
|
||||
private void InnerBrowserNavigating(object sender, NavigatingCancelEventArgs e)
|
||||
{
|
||||
if (_loaded)
|
||||
e.Cancel = true;
|
||||
_loaded = true;
|
||||
}
|
||||
|
||||
// re query the commands once done navigating.
|
||||
private void InnerBrowserNavigated(object sender, NavigationEventArgs e)
|
||||
{
|
||||
RegisterWindowErrorHanlder_();
|
||||
}
|
||||
|
||||
public void Navigate(string uri)
|
||||
{
|
||||
Url = uri;
|
||||
|
||||
if (_innerBrowser == null)
|
||||
return;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(uri) && Uri.IsWellFormedUriString(uri, UriKind.Absolute))
|
||||
try
|
||||
{
|
||||
_innerBrowser.Source = new Uri(uri);
|
||||
}
|
||||
catch (UriFormatException)
|
||||
{
|
||||
// just don't crash because of a malformed url
|
||||
}
|
||||
else
|
||||
_innerBrowser.Source = null;
|
||||
}
|
||||
|
||||
public void Navigate(Stream stream)
|
||||
{
|
||||
if (_innerBrowser == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
_innerBrowser.NavigateToStream(stream);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
// register script errors handler on DOM - document.window
|
||||
private void RegisterWindowErrorHanlder_()
|
||||
{
|
||||
object parwin = ((dynamic) _innerBrowser.Document).parentWindow;
|
||||
var cookie = new AxHost.ConnectionPointCookie(parwin, new HtmlWindowEvents2Impl(this),
|
||||
typeof(IIntHTMLWindowEvents2));
|
||||
// MemoryLEAK? No: cookie has a Finalize() to Disconnect istelf. We'll rely on that. If disconnected too early,
|
||||
// though (eg. in LoadCompleted-event) scripts continue to run and can cause error messages to appear again.
|
||||
// --> forget cookie and be happy.
|
||||
}
|
||||
|
||||
private void ApplyZoom()
|
||||
{
|
||||
if (_innerBrowser == null || !_innerBrowser.IsLoaded)
|
||||
return;
|
||||
|
||||
// grab a handle to the underlying ActiveX object
|
||||
IServiceProvider serviceProvider = null;
|
||||
if (_innerBrowser.Document != null)
|
||||
serviceProvider = (IServiceProvider) _innerBrowser.Document;
|
||||
if (serviceProvider == null)
|
||||
return;
|
||||
|
||||
var serviceGuid = SidSWebBrowserApp;
|
||||
var iid = typeof(IWebBrowser2).GUID;
|
||||
var browserInst =
|
||||
(IWebBrowser2) serviceProvider.QueryService(ref serviceGuid, ref iid);
|
||||
|
||||
try
|
||||
{
|
||||
object zoomPercObj = _zoom;
|
||||
// send the zoom command to the ActiveX object
|
||||
browserInst.ExecWB(OLECMDID.OLECMDID_OPTICAL_ZOOM,
|
||||
OLECMDEXECOPT.OLECMDEXECOPT_DONTPROMPTUSER,
|
||||
ref zoomPercObj,
|
||||
IntPtr.Zero);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignore this dynamic call if it fails.
|
||||
}
|
||||
}
|
||||
|
||||
// needed to implement the Event for script errors
|
||||
[Guid("3050f625-98b5-11cf-bb82-00aa00bdce0b")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
|
||||
[TypeLibType(TypeLibTypeFlags.FHidden)]
|
||||
[ComImport]
|
||||
private interface IIntHTMLWindowEvents2
|
||||
{
|
||||
[DispId(1002)]
|
||||
bool onerror(string description, string url, int line);
|
||||
}
|
||||
|
||||
// needed to implement the Event for script errors
|
||||
private class HtmlWindowEvents2Impl : IIntHTMLWindowEvents2
|
||||
{
|
||||
private readonly WpfWebBrowserWrapper _control;
|
||||
|
||||
public HtmlWindowEvents2Impl(WpfWebBrowserWrapper control)
|
||||
{
|
||||
_control = control;
|
||||
}
|
||||
|
||||
// implementation of the onerror Javascript error. Return true to indicate a "Handled" state.
|
||||
public bool onerror(string description, string urlString, int line)
|
||||
{
|
||||
Debug.WriteLine(description + "@" + urlString + ": " + line);
|
||||
// Handled:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Needed to expose the WebBrowser's underlying ActiveX control for zoom functionality
|
||||
[ComImport]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[Guid("6d5140c1-7436-11ce-8034-00aa006009fa")]
|
||||
internal interface IServiceProvider
|
||||
{
|
||||
[return: MarshalAs(UnmanagedType.IUnknown)]
|
||||
object QueryService(ref Guid guidService, ref Guid riid);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,16 +1,17 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
using QuickLook.Plugin.HtmlViewer;
|
||||
|
||||
namespace QuickLook.Plugin.MarkdownViewer
|
||||
{
|
||||
public class Plugin : IViewer
|
||||
{
|
||||
private WebkitPanel _panel;
|
||||
private WebpagePanel _panel;
|
||||
|
||||
public int Priority => int.MaxValue;
|
||||
public bool AllowsTransparency => true;
|
||||
public bool AllowsTransparency => false;
|
||||
|
||||
public bool CanHandle(string path)
|
||||
{
|
||||
@@ -20,6 +21,7 @@ namespace QuickLook.Plugin.MarkdownViewer
|
||||
switch (Path.GetExtension(path).ToLower())
|
||||
{
|
||||
case ".md":
|
||||
case ".rmd":
|
||||
return true;
|
||||
|
||||
default:
|
||||
@@ -36,13 +38,12 @@ namespace QuickLook.Plugin.MarkdownViewer
|
||||
|
||||
public void View(string path, ContextObject context)
|
||||
{
|
||||
_panel = new WebkitPanel();
|
||||
_panel = new WebpagePanel();
|
||||
context.ViewerContent = _panel;
|
||||
context.Title = Path.GetFileName(path);
|
||||
|
||||
_panel.LoadHtml(GenerateMarkdownHtml(path), path);
|
||||
|
||||
context.IsBusy = false;
|
||||
_panel.LoadHtml(GenerateMarkdownHtml(path));
|
||||
_panel.Dispatcher.Invoke(() => { context.IsBusy = false; }, DispatcherPriority.Loaded);
|
||||
}
|
||||
|
||||
public void Cleanup()
|
||||
|
Reference in New Issue
Block a user