'CefSharp FontResource ISchemeHandlerFactory
Is it possible to intercept the font request inside a CSS file?
We have the following CSS file:
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: local('Material Icons'),
local('MaterialIcons-Regular'),
url(MaterialIcons-Regular.woff2) format('woff2'),
url(MaterialIcons-Regular.woff) format('woff'),
url(MaterialIcons-Regular.ttf) format('truetype');
}
.material-icons {
/* ... */
}
The CSS file and the font file are embedded in our application. We added a CefCustomScheme and set a custom scheme handler factory as follows:
var settings = new CefSettings();
settings.RegisterScheme(new CefCustomScheme
{
SchemeName = SchemaName,
DomainName = WebViewDomainName,
SchemeHandlerFactory = new CustomSchemaHandlerFactory(),
IsFetchEnabled = true,
IsCorsEnabled = true,
IsSecure = true,
});
Custom SchemaHandlerFactory-Class and the resource handlers.
public class CustomSchemaHandlerFactory : ISchemeHandlerFactory
{
IResourceHandler ISchemeHandlerFactory.Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
{
if (request.ResourceType == ResourceType.Stylesheet)
return new StylesheetResourceHandler();
else if (request.ResourceType == ResourceType.FontResource)
return new FontResourceHandler();
return ResourceHandler.ForErrorMessage("File Not Found - " + request.Url, HttpStatusCode.NotFound);
}
public abstract class EmbeddedWebResourceHandler : ResourceHandler
{
private const string WebResource = "Dummy";
private static System.Reflection.Assembly Assembly;
protected Stream ReadResource(IRequest request)
{
if (Assembly == null)
Assembly = System.Reflection.Assembly.GetExecutingAssembly();
string resource = request.Url.Substring(7).Replace("/", ".");
string resourcePath = String.Concat(WebResource, resource);
return Assembly.GetManifestResourceStream(resourcePath);
}
}
public class StylesheetResourceHandler : EmbeddedWebResourceHandler
{
public override CefReturnValue ProcessRequestAsync(IRequest request, ICallback callback)
{
MimeType = "text/css";
Stream = ReadResource(request);
return CefReturnValue.Continue;
}
}
public class FontResourceHandler : EmbeddedWebResourceHandler
{
public override CefReturnValue ProcessRequestAsync(IRequest request, ICallback callback)
{
// This method is not invoked.
return base.ProcessRequestAsync(request, callback);
}
}
ISchemeHandlerFactory.Create is invoked for the CSS file. Unfortunately it does not work for the font file, which is loaded inside the CSS file.
If it is not possible to intercept the font request, are there any other options to make CEF "find" the font file? Like a browser font cache?
It is not an option to simply install the font on the PC of our users.
Solution 1:[1]
Well, it turns out that I was searching for resources with a wrong resource path.
If you embed resources as follows and you have folders with dashes in their names, %(RecursiveDir) will change dashes to underscores. In my case the folder material-icons was embedded as material_icons. This does not hold for %(FileName) (material-icons.css will stay material-icons.css).
<ItemGroup>
<EmbeddedResource Include="..\..\WebProject\WebProject\wwwroot\css\**\*.*">
<Link>WebResources\css\%(RecursiveDir)%(FileName)%(Extension)</Link>
</EmbeddedResource>
<EmbeddedResource Include="..\..\WebProject\WebProject\wwwroot\js\**\*.*">
<Link>WebResources\js\%(RecursiveDir)%(FileName)%(Extension)</Link>
</EmbeddedResource>
<EmbeddedResource Include="..\..\WebProject\WebProject\wwwroot\lib\**\*.*">
<Link>WebResources\lib\%(RecursiveDir)%(FileName)%(Extension)</Link>
</EmbeddedResource>
</ItemGroup>
My code basically looks like this now:
public class CustomSchemaHandlerFactory : ISchemeHandlerFactory
{
private const string WebResource = "Namespace.WebResources";
private static System.Reflection.Assembly Assembly;
protected Stream ReadResource(IRequest request)
{
if (Assembly == null)
Assembly = System.Reflection.Assembly.GetExecutingAssembly();
string resource = request.Url.Substring(SoPartWebView.BaseUrl.Length).Replace("/", ".");
string resourcePath = String.Concat(WebResource, resource);
var stream = Assembly.GetManifestResourceStream(resourcePath);
if (stream != null) return stream;
// Special case for the folder with the dash.
if (resource.StartsWith(".lib.material-icons"))
{
resourcePath = resourcePath.Replace(".lib.material-icons", ".lib.material_icons");
stream = Assembly.GetManifestResourceStream(resourcePath);
}
return stream;
}
IResourceHandler ISchemeHandlerFactory.Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
{
var fileExtension = Path.GetExtension(request.Url);
var mimeType = ResourceHandler.GetMimeType(fileExtension);
var stream = ReadResource(request);
return ResourceHandler.FromStream(stream, mimeType);
}
}
Anyway, it works now!
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | gaussdev |