Bug 1329314 - Add support for nsDisplayText webrender display item. r=jrmuizel?

This commit is contained in:
Mason Chang 2017-01-06 11:50:53 -08:00
parent 80b721469e
commit 5e1c34af71
14 changed files with 359 additions and 4 deletions

27
README.displayitem Normal file
View File

@ -0,0 +1,27 @@
How to add a new WebRender display item from a Gecko Display item, the general flow is to:
(1) Force layout to create a new active layer for the gecko display item.
(2) Plumb the data needed for the display item from content through WebRenderBridgeParent on the parent side.
(3) From WebRenderBridgeParent, call out into bindings.rs and implement the appropriate WR calls.
More detailed steps are:
1) Force layout to create an active layer for the gecko display item.
See http://searchfox.org/mozilla-central/rev/0f254a30d684796bcc8b6e2a102a0095d25842bb/layout/generic/nsTextFrame.cpp#4983
as an example for text layers. Ping Matt Woodrow or Markus Stange for help.
The Active layer part comes from nsDisplayText::GetLayerState
2) Create the new display item layer:
See text layer:
http://searchfox.org/mozilla-central/rev/0f254a30d684796bcc8b6e2a102a0095d25842bb/gfx/layers/Layers.h#2403
The layer should have all the information to display the item.
3) Create the WebRender equivalent layer. In YourLayerType::RenderLayer, serialize the data needed for the layer type.
4) If you need to add a custom IPC serialization mechanism, do it in WebRenderTypes.h
5) Create a WebRender command to process the new layer type in WebRenderMessages.ipdlh. These are the struct OpDPPushYourLayerTypeHere
6) Add a new function in WebRender.h that will call out into webrender to render your display item.
7) In WebRenderBridgeParent::ProcessWebRenderCommands, call out to the new function in (6).
8) Fill out the function in (6) in bindings.rs to make webrender do the right thing. Generally, it's just push a display item.

View File

@ -716,6 +716,8 @@ public:
virtual bool GetFontDescriptor(FontDescriptorOutput, void *) { return false; }
virtual bool CanSerialize() { return false; }
void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) {
mUserData.Add(key, userData, destroy);
}

View File

@ -228,6 +228,10 @@ ScaledFontDWrite::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton
return false;
}
if (!aDataCallback) {
return true;
}
RefPtr<IDWriteFontFile> file;
mFontFace->GetFiles(&fileCount, getter_AddRefs(file));

View File

@ -40,6 +40,8 @@ public:
virtual bool GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton);
virtual bool CanSerialize() override { return true; }
virtual AntialiasMode GetDefaultAAMode() override;
bool UseEmbeddedBitmaps() { return mUseEmbeddedBitmap; }

View File

@ -15,8 +15,10 @@ using WRColor from "mozilla/gfx/webrender.h";
using WRImageKey from "mozilla/gfx/webrender.h";
using WRLayoutSize from "mozilla/gfx/webrender.h";
using WRRect from "mozilla/gfx/webrender.h";
using WRGlyphArray from "mozilla/gfx/webrender.h";
using MaybeImageMask from "mozilla/layers/WebRenderTypes.h";
using mozilla::gfx::Matrix4x4 from "mozilla/gfx/Matrix.h";
using mozilla::gfx::ByteBuffer from "mozilla/layers/WebRenderTypes.h";
namespace mozilla {
namespace layers {
@ -72,6 +74,16 @@ struct OpDPPushIframe {
uint64_t layersid;
};
struct OpDPPushText {
WRRect bounds;
WRRect clip;
WRGlyphArray[] glyph_array;
uint32_t font_index;
float glyph_size;
ByteBuffer font_buffer;
uint32_t font_buffer_length;
};
union WebRenderCommand {
OpDPPushStackingContext;
OpDPPopStackingContext;
@ -80,6 +92,7 @@ union WebRenderCommand {
OpDPPushImage;
OpDPPushExternalImageId;
OpDPPushIframe;
OpDPPushText;
CompositableOperation;
};

View File

@ -384,6 +384,7 @@ UNIFIED_SOURCES += [
'wr/WebRenderImageLayer.cpp',
'wr/WebRenderLayerManager.cpp',
'wr/WebRenderPaintedLayer.cpp',
'wr/WebRenderTextLayer.cpp',
]
SOURCES += [

View File

@ -323,6 +323,27 @@ WebRenderBridgeParent::ProcessWebrenderCommands(InfallibleTArray<WebRenderComman
}
break;
}
case WebRenderCommand::TOpDPPushText: {
const OpDPPushText& op = cmd.get_OpDPPushText();
const nsTArray<WRGlyphArray>& glyph_array = op.glyph_array();
for (size_t i = 0; i < glyph_array.Length(); i++) {
const nsTArray<WRGlyphInstance>& glyphs = glyph_array[i].glyphs;
wr_dp_push_text(mWRWindowState,
mWRState,
op.bounds(),
op.clip(),
glyph_array[i].color,
glyphs.Elements(),
glyphs.Length(),
op.glyph_size(),
op.font_buffer().mData,
op.font_buffer_length());
}
break;
}
default:
NS_RUNTIMEABORT("not reached");
}

View File

@ -22,6 +22,7 @@
#include "WebRenderContainerLayer.h"
#include "WebRenderImageLayer.h"
#include "WebRenderPaintedLayer.h"
#include "WebRenderTextLayer.h"
namespace mozilla {
@ -472,7 +473,7 @@ WebRenderLayerManager::CreateRefLayer()
already_AddRefed<TextLayer>
WebRenderLayerManager::CreateTextLayer()
{
return nullptr;
return MakeAndAddRef<WebRenderTextLayer>(this);
}
already_AddRefed<BorderLayer>

View File

@ -0,0 +1,77 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebRenderTextLayer.h"
namespace mozilla {
namespace layers {
using namespace mozilla::gfx;
static void
DWriteFontFileData(const uint8_t* aData, uint32_t aLength, uint32_t aIndex,
float aGlyphSize, void* aBaton)
{
WebRenderTextLayer* layer = static_cast<WebRenderTextLayer*>(aBaton);
uint8_t* fontData = (uint8_t*)malloc(aLength * sizeof(uint8_t));
memcpy(fontData, aData, aLength * sizeof(uint8_t));
layer->mFontData = fontData;
layer->mFontDataLength = aLength;
layer->mIndex = aIndex;
layer->mGlyphSize = aGlyphSize;
}
void
WebRenderTextLayer::RenderLayer()
{
if (mBounds.IsEmpty()) {
return;
}
gfx::Rect rect = RelativeToParent(GetTransform().TransformBounds(IntRectToRect(mBounds)));
gfx::Rect clip;
if (GetClipRect().isSome()) {
clip = RelativeToParent(IntRectToRect(GetClipRect().ref().ToUnknownRect()));
} else {
clip = rect;
}
MOZ_ASSERT(mFont->GetType() == FontType::DWRITE);
mFont->GetFontFileData(&DWriteFontFileData, this);
gfx::ByteBuffer fontBuffer(mFontDataLength, mFontData);
nsTArray<WRGlyphArray> wr_glyphs;
wr_glyphs.SetLength(mGlyphs.Length());
for (size_t i = 0; i < mGlyphs.Length(); i++) {
GlyphArray glyph_array = mGlyphs[i];
nsTArray<Glyph>& glyphs = glyph_array.glyphs();
nsTArray<WRGlyphInstance>& wr_glyph_instances = wr_glyphs[i].glyphs;
wr_glyph_instances.SetLength(glyphs.Length());
wr_glyphs[i].color = toWrColor(glyph_array.color().value());
for (size_t j = 0; j < glyphs.Length(); j++) {
wr_glyph_instances[j].index = glyphs[j].mIndex;
wr_glyph_instances[j].x = glyphs[j].mPosition.x;
wr_glyph_instances[j].y = glyphs[j].mPosition.y;
}
}
WRBridge()->AddWebRenderCommand(OpDPPushText(
toWrRect(rect),
toWrRect(clip),
wr_glyphs,
mIndex,
mGlyphSize,
fontBuffer,
mFontDataLength
));
}
} // namespace layers
} // namespace mozilla

View File

@ -0,0 +1,51 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GFX_WEBRENDERTEXTLAYER_H
#define GFX_WEBRENDERTEXTLAYER_H
#include "Layers.h"
#include "WebRenderLayerManager.h"
namespace mozilla {
namespace layers {
class WebRenderTextLayer : public WebRenderLayer,
public TextLayer {
public:
explicit WebRenderTextLayer(WebRenderLayerManager* aLayerManager)
: TextLayer(aLayerManager, static_cast<WebRenderLayer*>(this))
, mFontData(nullptr)
, mFontDataLength(0)
, mIndex(0)
, mGlyphSize(0.0)
{
MOZ_COUNT_CTOR(WebRenderTextLayer);
}
protected:
virtual ~WebRenderTextLayer()
{
MOZ_COUNT_DTOR(WebRenderTextLayer);
if (mFontData) {
free(mFontData);
}
}
public:
Layer* GetLayer() override { return this; }
void RenderLayer() override;
uint8_t* mFontData;
uint32_t mFontDataLength;
uint32_t mIndex;
float mGlyphSize;
};
} // namespace layers
} // namespace mozilla
#endif // GFX_WEBRENDERTEXTLAYER_H

View File

@ -49,6 +49,11 @@ struct ByteBuffer
}
}
bool operator==(const ByteBuffer& other) const {
return mLength == other.mLength &&
!(memcmp(mData, other.mData, mLength));
}
size_t mLength;
uint8_t* mData;
bool mOwned;
@ -139,6 +144,66 @@ struct ParamTraits<WRColor>
}
};
template<>
struct ParamTraits<WRGlyphInstance>
{
static void
Write(Message* aMsg, const WRGlyphInstance& aParam)
{
WriteParam(aMsg, aParam.index);
WriteParam(aMsg, aParam.x);
WriteParam(aMsg, aParam.y);
}
static bool
Read(const Message* aMsg, PickleIterator* aIter, WRGlyphInstance* aResult)
{
return ReadParam(aMsg, aIter, &aResult->index)
&& ReadParam(aMsg, aIter, &aResult->x)
&& ReadParam(aMsg, aIter, &aResult->y);
}
};
template<>
struct ParamTraits<WRGlyphArray>
{
static void
Write(Message* aMsg, const WRGlyphArray& aParam)
{
WriteParam(aMsg, aParam.color);
size_t length = aParam.glyphs.Length();
WriteParam(aMsg, length);
for (size_t i = 0; i < length; i++) {
WriteParam(aMsg, aParam.glyphs[i]);
}
}
static bool
Read(const Message* aMsg, PickleIterator* aIter, WRGlyphArray* aResult)
{
if (!ReadParam(aMsg, aIter, &aResult->color)) {
return false;
}
size_t length;
if (!ReadParam(aMsg, aIter, &length)) {
return false;
}
aResult->glyphs.SetLength(length);
for (size_t i = 0; i < length; i++) {
if (!ReadParam(aMsg, aIter, &aResult->glyphs[i])) {
return false;
}
}
return true;
}
};
template<>
struct ParamTraits<WRBorderSide>
{

View File

@ -7,7 +7,7 @@ use std::os::raw::{c_void, c_char};
use gleam::gl;
use webrender_traits::{BorderSide, BorderStyle, BorderRadius};
use webrender_traits::{PipelineId, ClipRegion};
use webrender_traits::{Epoch, ColorF};
use webrender_traits::{Epoch, ColorF, GlyphInstance};
use webrender_traits::{ImageData, ImageFormat, ImageKey, ImageMask, ImageRendering, RendererKind};
use webrender_traits::{ExternalImageId};
use webrender_traits::{DeviceUintSize};
@ -15,6 +15,8 @@ use webrender_traits::{LayoutPoint, LayoutRect, LayoutSize, LayoutTransform};
use webrender::renderer::{Renderer, RendererOptions};
use webrender::renderer::{ExternalImage, ExternalImageHandler, ExternalImageSource};
use std::sync::{Arc, Mutex, Condvar};
use app_units::Au;
extern crate webrender_traits;
fn get_proc_address(glcontext_ptr: *mut c_void, name: &str) -> *const c_void{
@ -573,3 +575,43 @@ pub extern fn wr_profiler_set_enabled(window: &mut WrWindowState, enabled: bool)
assert!( unsafe { is_in_compositor_thread() });
window.renderer.set_profiler_enabled(enabled);
}
#[no_mangle]
pub extern fn wr_dp_push_text(window: &mut WrWindowState,
state: &mut WrState,
bounds: WrRect,
clip: WrRect,
color: WrColor,
glyphs: *mut GlyphInstance,
glyph_count: u32,
glyph_size: f32,
font_buffer: *mut u8,
buffer_size: usize)
{
assert!( unsafe { is_in_compositor_thread() });
let font_slice = unsafe {
slice::from_raw_parts(font_buffer, buffer_size as usize)
};
let mut font_vector = Vec::new();
font_vector.extend_from_slice(font_slice);
let font_key = window.api.add_raw_font(font_vector);
let glyph_slice = unsafe {
slice::from_raw_parts(glyphs, glyph_count as usize)
};
let mut glyph_vector = Vec::new();
glyph_vector.extend_from_slice(&glyph_slice);
let colorf = ColorF::new(color.r, color.g, color.b, color.a);
let clip_region = state.frame_builder.dl_builder.new_clip_region(&clip.to_rect(), Vec::new(), None);
state.frame_builder.dl_builder.push_text(bounds.to_rect(),
clip_region,
glyph_vector,
font_key,
colorf,
Au::from_f32_px(glyph_size),
Au::from_px(0));
}

View File

@ -6,6 +6,9 @@
#ifndef WR_h
#define WR_h
#include "mozilla/layers/LayersMessages.h"
extern "C" {
bool is_in_compositor_thread();
void* get_proc_address_from_glcontext(void* glcontext_ptr, const char* procname);
@ -39,6 +42,42 @@ struct WRColor {
}
};
struct WRGlyphInstance {
uint32_t index;
float x;
float y;
bool operator==(const WRGlyphInstance& other) const {
return index == other.index &&
x == other.x &&
y == other.y;
}
};
// Note that the type is slightly different than
// the definition in bindings.rs. WRGlyphInstance
// versus GlyphInstance, but their layout is the same.
// So we're really overlapping the types for the same memory.
struct WRGlyphArray {
WRColor color;
nsTArray<WRGlyphInstance> glyphs;
bool operator==(const WRGlyphArray& other) const {
if (!(color == other.color) ||
(glyphs.Length() != other.glyphs.Length())) {
return false;
}
for (size_t i = 0; i < glyphs.Length(); i++) {
if (!(glyphs[i] == other.glyphs[i])) {
return false;
}
}
return true;
}
};
enum WRBorderStyle {
None,
Solid,
@ -238,6 +277,14 @@ WR_INLINE void
wr_profiler_set_enabled(wrwindowstate* wrWindow, bool enabled)
WR_FUNC;
WR_INLINE void
wr_dp_push_text(wrwindowstate* wrWindow, wrstate* wrState,
WRRect bounds, WRRect clip,
WRColor color, const WRGlyphInstance* glyphs,
uint32_t glyph_count, float glyph_size,
uint8_t* font_buffer, uint32_t buffer_size)
WR_FUNC;
#undef WR_FUNC
}
#endif

View File

@ -4994,7 +4994,9 @@ nsDisplayText::nsDisplayText(nsDisplayListBuilder* aBuilder, nsTextFrame* aFrame
GlyphArray* g = mGlyphs.AppendElement();
std::vector<Glyph> glyphs;
Color color;
if (!capture->ContainsOnlyColoredGlyphs(mFont, color, glyphs)) {
if (!capture->ContainsOnlyColoredGlyphs(mFont, color, glyphs)
|| !mFont->CanSerialize()
|| XRE_IsParentProcess()) {
mFont = nullptr;
mGlyphs.Clear();
} else {
@ -5011,7 +5013,7 @@ nsDisplayText::GetLayerState(nsDisplayListBuilder* aBuilder,
const ContainerLayerParameters& aParameters)
{
if (mFont) {
return mozilla::LAYER_INACTIVE;
return mozilla::LAYER_ACTIVE;
}
MOZ_ASSERT(mMergedFrames.IsEmpty());
return mozilla::LAYER_NONE;