Merge mozilla-inbound and mozulla-central

This commit is contained in:
Marco Bonardo 2011-07-05 14:02:19 +02:00
Родитель e3ad005a6c 9a97cc1996
Коммит e2c04d1fe3
28 изменённых файлов: 3391 добавлений и 1409 удалений

Просмотреть файл

@ -510,9 +510,11 @@ protected:
{
ContextState& state = CurrentState();
// The spec says we should not draw shadows when the alpha value is 0,
// regardless of the operator being used.
return state.StyleIsColor(STYLE_SHADOW) &&
NS_GET_A(state.colorStyles[STYLE_SHADOW]) > 0 &&
mThebes->CurrentOperator() == gfxContext::OPERATOR_OVER;
(state.shadowOffset != gfxPoint(0, 0) || state.shadowBlur != 0);
}
/**

Просмотреть файл

@ -621,7 +621,18 @@ protected:
// The spec says we should not draw shadows if the operator is OVER.
// If it's over and the alpha value is zero, nothing needs to be drawn.
return state.op == OP_OVER && NS_GET_A(state.shadowColor) != 0;
return NS_GET_A(state.shadowColor) != 0 &&
(state.shadowBlur != 0 || state.shadowOffset.x != 0 || state.shadowOffset.y != 0);
}
CompositionOp UsedOperation()
{
if (NeedToDrawShadow()) {
// In this case the shadow rendering will use the operator.
return OP_OVER;
}
return CurrentState().op;
}
/**
@ -928,7 +939,8 @@ protected:
mCtx->mTarget->DrawSurfaceWithShadow(snapshot, mSurfOffset,
Color::FromABGR(mCtx->CurrentState().shadowColor),
mCtx->CurrentState().shadowOffset, mSigma);
mCtx->CurrentState().shadowOffset, mSigma,
mCtx->CurrentState().op);
}
DrawTarget* operator->()
@ -2136,7 +2148,7 @@ nsCanvasRenderingContext2DAzure::FillRect(float x, float y, float w, float h)
AdjustedTarget(this)->FillRect(mgfx::Rect(x, y, w, h),
GeneralPattern().ForStyle(this, STYLE_FILL, mTarget),
DrawOptions(state.globalAlpha, state.op));
DrawOptions(state.globalAlpha, UsedOperation()));
return RedrawUser(gfxRect(x, y, w, h));
}
@ -2165,7 +2177,7 @@ nsCanvasRenderingContext2DAzure::StrokeRect(float x, float y, float w, float h)
state.dash.Length(),
state.dash.Elements(),
state.dashOffset),
DrawOptions(state.globalAlpha, state.op));
DrawOptions(state.globalAlpha, UsedOperation()));
return NS_OK;
} else if (!w) {
CapStyle cap = CAP_BUTT;
@ -2180,7 +2192,7 @@ nsCanvasRenderingContext2DAzure::StrokeRect(float x, float y, float w, float h)
state.dash.Length(),
state.dash.Elements(),
state.dashOffset),
DrawOptions(state.globalAlpha, state.op));
DrawOptions(state.globalAlpha, UsedOperation()));
return NS_OK;
}
@ -2192,7 +2204,7 @@ nsCanvasRenderingContext2DAzure::StrokeRect(float x, float y, float w, float h)
state.dash.Length(),
state.dash.Elements(),
state.dashOffset),
DrawOptions(state.globalAlpha, state.op));
DrawOptions(state.globalAlpha, UsedOperation()));
return Redraw();
}
@ -2236,7 +2248,7 @@ nsCanvasRenderingContext2DAzure::Fill()
AdjustedTarget(this)->
Fill(mPath, GeneralPattern().ForStyle(this, STYLE_FILL, mTarget),
DrawOptions(CurrentState().globalAlpha, CurrentState().op));
DrawOptions(CurrentState().globalAlpha, UsedOperation()));
return Redraw();
}
@ -2259,7 +2271,7 @@ nsCanvasRenderingContext2DAzure::Stroke()
state.dash.Length(),
state.dash.Elements(),
state.dashOffset),
DrawOptions(state.globalAlpha, state.op));
DrawOptions(state.globalAlpha, UsedOperation()));
return Redraw();
}
@ -3133,7 +3145,7 @@ struct NS_STACK_CLASS nsCanvasBidiProcessorAzure : public nsBidiPresUtils::BidiP
FillGlyphs(scaledFont, buffer,
nsCanvasRenderingContext2DAzure::GeneralPattern().
ForStyle(mCtx, nsCanvasRenderingContext2DAzure::STYLE_FILL, mCtx->mTarget),
DrawOptions(mState->globalAlpha, mState->op));
DrawOptions(mState->globalAlpha, mCtx->UsedOperation()));
} else if (mOp == nsCanvasRenderingContext2DAzure::TEXT_DRAW_OPERATION_STROKE) {
RefPtr<Path> path = scaledFont->GetPathForGlyphs(buffer, mCtx->mTarget);
@ -3148,7 +3160,7 @@ struct NS_STACK_CLASS nsCanvasBidiProcessorAzure : public nsBidiPresUtils::BidiP
state.dash.Length(),
state.dash.Elements(),
state.dashOffset),
DrawOptions(state.globalAlpha, state.op));
DrawOptions(state.globalAlpha, mCtx->UsedOperation()));
}
}
@ -3784,7 +3796,7 @@ nsCanvasRenderingContext2DAzure::DrawImage(nsIDOMElement *imgElt, float a1,
mgfx::Rect(dx, dy, dw, dh),
mgfx::Rect(sx, sy, sw, sh),
DrawSurfaceOptions(filter),
DrawOptions(CurrentState().globalAlpha, CurrentState().op));
DrawOptions(CurrentState().globalAlpha, UsedOperation()));
return RedrawUser(gfxRect(dx, dy, dw, dh));
}

Просмотреть файл

@ -87,7 +87,6 @@ _TEST_FILES_0 = \
test_canvas_strokeStyle_getter.html \
test_bug613794.html \
test_drawImage_edge_cases.html \
test_shadow_operators.html \
$(NULL)
ifneq (1_Linux,$(MOZ_SUITE)_$(OS_ARCH))

Просмотреть файл

@ -16742,7 +16742,7 @@ ctx.shadowOffsetX = 100;
ctx.fillStyle = '#0f0';
ctx.fillRect(-100, 0, 200, 50);
isPixel(ctx, 50, 25, 255, 255, 0, 255, 2);
isPixel(ctx, 50, 25, 0, 255, 0, 255, 2);
}
</script>
@ -16768,7 +16768,7 @@ ctx.shadowBlur = 1;
ctx.fillStyle = '#0f0';
ctx.fillRect(-10, -10, 120, 70);
isPixel(ctx, 50, 25, 255, 255, 0, 255, 2);
isPixel(ctx, 50, 25, 0, 255, 0, 255, 2);
}
</script>
@ -21501,14 +21501,13 @@ function runTests() {
//test_2d_composite_uncovered_pattern_source_in();
//test_2d_composite_uncovered_pattern_source_out();
//test_2d_path_rect_zero_6(); // This test is bogus according to the spec; see bug 407107
// The following tests are disabled due to pending changes in the spec:
//
//test_2d_shadow_composite_3();
//test_2d_path_rect_zero_6(); // This test is bogus according to the spec; see bug 407107
// These tests are bogus according to the spec: shadows should not be
// drawn if shadowBlur, shadowOffsetX, and shadowOffsetY are all zero, whic
// they are in these tests
//test_2d_shadow_composite_3();
//test_2d_shadow_composite_4();
//test_2d_shadow_composite_1();
//test_2d_shadow_composite_2();
try {
test_2d_canvas_readonly();
} catch (e) {
@ -23894,6 +23893,16 @@ function runTests() {
} catch (e) {
ok(false, "unexpected exception thrown in: test_2d_shadow_clip_3");
}
try {
test_2d_shadow_composite_1();
} catch (e) {
ok(false, "unexpected exception thrown in: test_2d_shadow_composite_1");
}
try {
test_2d_shadow_composite_2();
} catch (e) {
ok(false, "unexpected exception thrown in: test_2d_shadow_composite_2");
}
try {
test_2d_shadow_gradient_alpha();
} catch (e) {

Просмотреть файл

@ -1,91 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display">
<canvas id="c" width="2" height="2"></canvas>
<canvas id="c2" width="2" height="2"></canvas>
</p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
function isPixel(ctx, x,y, r,g,b,a, d) {
var pos = x + "," + y;
var colour = r + "," + g + "," + b + "," + a;
var pixel = ctx.getImageData(x, y, 1, 1);
var pr = pixel.data[0],
pg = pixel.data[1],
pb = pixel.data[2],
pa = pixel.data[3];
ok(r-d <= pr && pr <= r+d &&
g-d <= pg && pg <= g+d &&
b-d <= pb && pb <= b+d &&
a-d <= pa && pa <= a+d,
"pixel "+pos+" of "+ctx.canvas.id+" is "+pr+","+pg+","+pb+","+pa+"; expected "+colour+" +/- "+d);
}
function isSamePixel(ctx,ctx2, x,y, d) {
var pos = x + "," + y;
var pixel = ctx.getImageData(x, y, 1, 1);
var pixel2 = ctx2.getImageData(x, y, 1, 1);
var pr = pixel.data[0],
pg = pixel.data[1],
pb = pixel.data[2],
pa = pixel.data[3];
var r = pixel2.data[0],
g = pixel2.data[1],
b = pixel2.data[2],
a = pixel2.data[3];
var colour = r + "," + g + "," + b + "," + a;
ok(r-d <= pr && pr <= r+d &&
g-d <= pg && pg <= g+d &&
b-d <= pb && pb <= b+d &&
a-d <= pa && pa <= a+d,
"pixel "+pos+" of "+ctx.canvas.id+" is "+pr+","+pg+","+pb+","+pa+"; expected "+colour+" +/- "+d);
}
var c = document.getElementById("c");
var ctx = c.getContext("2d");
ctx.shadowColor = "rgb(0,255,0)";
// Test that shadows with zero blur and offset are drawn
ctx.fillStyle = "rgba(0,0,255,0.5)";
ctx.fillRect(0, 0, 1, 1);
isPixel(ctx, 0,0, 0,85,170,192, 1);
// Test that non-OVER operators do not draw shadows
var c2 = document.getElementById("c2");
var ctx2 = c2.getContext("2d");
var operators = ["source-atop", "source-in", "source-out", "destination-atop",
"destination-in", "destination-out", "destination-over", "lighter", "copy",
"xor"];
ctx.shadowOffsetX = ctx.shadowOffsetY = 1;
for (var i = 0; i < operators.length; ++i) {
ctx.fillStyle = "red";
ctx.fillRect(0, 0, 2, 2);
ctx.globalCompositeOperation = operators[i];
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, 1, 1);
ctx2.fillStyle = "red";
ctx2.fillRect(0, 0, 2, 2);
ctx2.globalCompositeOperation = operators[i];
ctx2.fillStyle = "blue";
ctx2.fillRect(0, 0, 1, 1);
isSamePixel(ctx,ctx2, 1,1, 0);
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -483,12 +483,14 @@ public:
* aColor Color of the drawn shadow
* aOffset Offset of the shadow
* aSigma Sigma used for the guassian filter kernel
* aOperator Composition operator used
*/
virtual void DrawSurfaceWithShadow(SourceSurface *aSurface,
const Point &aDest,
const Color &aColor,
const Point &aOffset,
Float aSigma) = 0;
Float aSigma,
CompositionOp aOperator) = 0;
/*
* Clear a rectangle on the draw target to transparent black. This will

Просмотреть файл

@ -63,7 +63,8 @@ public:
const Point &aDest,
const Color &aColor,
const Point &aOffset,
Float aSigma)
Float aSigma,
CompositionOp aOperator)
{ }
virtual void ClearRect(const Rect &aRect)

Просмотреть файл

@ -122,29 +122,7 @@ public:
gfxWarning() << "Failed to create shared bitmap for old surface.";
}
factory()->CreatePathGeometry(byRef(mClippedArea));
RefPtr<ID2D1GeometrySink> currentSink;
mClippedArea->Open(byRef(currentSink));
std::vector<DrawTargetD2D::PushedClip>::iterator iter = mDT->mPushedClips.begin();
iter->mPath->GetGeometry()->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES,
iter->mTransform, currentSink);
currentSink->Close();
iter++;
for (;iter != mDT->mPushedClips.end(); iter++) {
RefPtr<ID2D1PathGeometry> newGeom;
factory()->CreatePathGeometry(byRef(newGeom));
newGeom->Open(byRef(currentSink));
mClippedArea->CombineWithGeometry(iter->mPath->GetGeometry(), D2D1_COMBINE_MODE_INTERSECT,
iter->mTransform, currentSink);
currentSink->Close();
mClippedArea = newGeom;
}
mClippedArea = mDT->GetClippedGeometry();
}
ID2D1Factory *factory() { return mDT->factory(); }
@ -163,7 +141,9 @@ public:
mDT->mTransformDirty = true;
RefPtr<ID2D1RectangleGeometry> rectGeom;
factory()->CreateRectangleGeometry(D2D1::InfiniteRect(), byRef(rectGeom));
factory()->CreateRectangleGeometry(
D2D1::RectF(0, 0, float(mDT->mSize.width), float(mDT->mSize.height)),
byRef(rectGeom));
RefPtr<ID2D1PathGeometry> invClippedArea;
factory()->CreatePathGeometry(byRef(invClippedArea));
@ -188,7 +168,7 @@ private:
// with the old dest surface data.
RefPtr<ID2D1Bitmap> mOldSurfBitmap;
// This contains the area drawing is clipped to.
RefPtr<ID2D1PathGeometry> mClippedArea;
RefPtr<ID2D1Geometry> mClippedArea;
};
DrawTargetD2D::DrawTargetD2D()
@ -307,7 +287,8 @@ DrawTargetD2D::DrawSurfaceWithShadow(SourceSurface *aSurface,
const Point &aDest,
const Color &aColor,
const Point &aOffset,
Float aSigma)
Float aSigma,
CompositionOp aOperator)
{
RefPtr<ID3D10ShaderResourceView> srView = NULL;
if (aSurface->GetType() != SURFACE_D2D1_DRAWTARGET) {
@ -316,6 +297,12 @@ DrawTargetD2D::DrawSurfaceWithShadow(SourceSurface *aSurface,
Flush();
AutoSaveRestoreClippedOut restoreClippedOut(this);
if (!IsOperatorBoundByMask(aOperator)) {
restoreClippedOut.Save();
}
srView = static_cast<SourceSurfaceD2DTarget*>(aSurface)->GetSRView();
EnsureViews();
@ -330,35 +317,36 @@ DrawTargetD2D::DrawSurfaceWithShadow(SourceSurface *aSurface,
}
}
RefPtr<ID3D10RenderTargetView> destRTView = mRTView;
RefPtr<ID3D10Texture2D> destTexture;
HRESULT hr;
RefPtr<ID3D10Texture2D> maskTexture;
RefPtr<ID3D10ShaderResourceView> maskSRView;
if (mPushedClips.size()) {
// We need to take clips into account, draw into a temporary surface, which
// we then blend back with the proper clips set, using D2D.
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_A8_UNORM,
mSize.width, mSize.height,
1, 1);
desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
hr = mDevice->CreateTexture2D(&desc, NULL, byRef(destTexture));
if (FAILED(hr)) {
gfxWarning() << "Failure to create temporary texture. Size: " << mSize << " Code: " << hr;
return;
}
hr = mDevice->CreateTexture2D(&desc, NULL, byRef(maskTexture));
hr = mDevice->CreateRenderTargetView(destTexture, NULL, byRef(destRTView));
if (FAILED(hr)) {
gfxWarning() << "Failure to create RenderTargetView. Code: " << hr;
return;
}
RefPtr<ID2D1RenderTarget> rt = CreateRTForTexture(maskTexture);
float color[4] = { 0, 0, 0, 0 };
mDevice->ClearRenderTargetView(destRTView, color);
RefPtr<ID2D1SolidColorBrush> brush;
rt->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), byRef(brush));
RefPtr<ID2D1Geometry> geometry = GetClippedGeometry();
rt->BeginDraw();
rt->Clear(D2D1::ColorF(0, 0));
rt->FillGeometry(geometry, brush);
rt->EndDraw();
mDevice->CreateShaderResourceView(maskTexture, NULL, byRef(maskSRView));
}
IntSize srcSurfSize;
ID3D10RenderTargetView *rtViews;
D3D10_VIEWPORT viewport;
@ -526,6 +514,10 @@ DrawTargetD2D::DrawSurfaceWithShadow(SourceSurface *aSurface,
if (!needBiggerTemp) {
tmpRTView = mTempRTView;
tmpSRView = mSRView;
// There could still be content here!
float color[4] = { 0, 0, 0, 0 };
mDevice->ClearRenderTargetView(tmpRTView, color);
} else {
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
srcSurfSize.width,
@ -591,8 +583,19 @@ DrawTargetD2D::DrawSurfaceWithShadow(SourceSurface *aSurface,
SetFloatVector(ShaderConstantRectD3D10(-correctedOffset.x / Float(tmpSurfSize.width), -correctedOffset.y / Float(tmpSurfSize.height),
mSize.width / Float(tmpSurfSize.width) * dsFactorX,
mSize.height / Float(tmpSurfSize.height) * dsFactorY));
mPrivateData->mEffect->GetTechniqueByName("SampleTextureWithShadow")->
GetPassByIndex(1)->Apply(0);
if (mPushedClips.size()) {
mPrivateData->mEffect->GetVariableByName("mask")->AsShaderResource()->SetResource(maskSRView);
mPrivateData->mEffect->GetVariableByName("MaskTexCoords")->AsVector()->
SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f));
mPrivateData->mEffect->GetTechniqueByName("SampleTextureWithShadow")->
GetPassByIndex(2)->Apply(0);
} else {
mPrivateData->mEffect->GetTechniqueByName("SampleTextureWithShadow")->
GetPassByIndex(1)->Apply(0);
}
mDevice->OMSetBlendState(GetBlendStateForOperator(aOperator), NULL, 0xffffffff);
mDevice->Draw(4, 0);
@ -601,39 +604,17 @@ DrawTargetD2D::DrawSurfaceWithShadow(SourceSurface *aSurface,
SetFloatVector(ShaderConstantRectD3D10(-aDest.x / aSurface->GetSize().width, -aDest.y / aSurface->GetSize().height,
Float(mSize.width) / aSurface->GetSize().width,
Float(mSize.height) / aSurface->GetSize().height));
mPrivateData->mEffect->GetTechniqueByName("SampleTexture")->
GetPassByIndex(0)->Apply(0);
mDevice->OMSetBlendState(GetBlendStateForOperator(OP_OVER), NULL, 0xffffffff);
if (mPushedClips.size()) {
mPrivateData->mEffect->GetTechniqueByName("SampleMaskedTexture")->
GetPassByIndex(0)->Apply(0);
} else {
mPrivateData->mEffect->GetTechniqueByName("SampleTexture")->
GetPassByIndex(0)->Apply(0);
}
mDevice->OMSetBlendState(GetBlendStateForOperator(aOperator), NULL, 0xffffffff);
mDevice->Draw(4, 0);
if (mPushedClips.size()) {
// Assert destTexture
// Blend back using the proper clips.
PrepareForDrawing(mRT);
RefPtr<IDXGISurface> surf;
hr = destTexture->QueryInterface((IDXGISurface**) byRef(surf));
if (FAILED(hr)) {
gfxWarning() << "Failure to QI texture to surface. Code: " << hr;
return;
}
D2D1_BITMAP_PROPERTIES props =
D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(mFormat), AlphaMode(mFormat)));
RefPtr<ID2D1Bitmap> bitmap;
hr = mRT->CreateSharedBitmap(IID_IDXGISurface, surf,
&props, byRef(bitmap));
if (FAILED(hr)) {
gfxWarning() << "Failure to create shared bitmap for surface. Code: " << hr;
return;
}
mRT->DrawBitmap(bitmap);
}
}
void
@ -1409,6 +1390,38 @@ DrawTargetD2D::FinalizeRTForOperator(CompositionOp aOperator, const Rect &aBound
mDevice->Draw(4, 0);
}
TemporaryRef<ID2D1Geometry>
DrawTargetD2D::GetClippedGeometry()
{
RefPtr<ID2D1GeometrySink> currentSink;
RefPtr<ID2D1PathGeometry> clippedGeometry;
factory()->CreatePathGeometry(byRef(clippedGeometry));
clippedGeometry->Open(byRef(currentSink));
std::vector<DrawTargetD2D::PushedClip>::iterator iter = mPushedClips.begin();
iter->mPath->GetGeometry()->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES,
iter->mTransform, currentSink);
currentSink->Close();
iter++;
for (;iter != mPushedClips.end(); iter++) {
RefPtr<ID2D1PathGeometry> newGeom;
factory()->CreatePathGeometry(byRef(newGeom));
newGeom->Open(byRef(currentSink));
clippedGeometry->CombineWithGeometry(iter->mPath->GetGeometry(), D2D1_COMBINE_MODE_INTERSECT,
iter->mTransform, currentSink);
currentSink->Close();
clippedGeometry = newGeom;
}
return clippedGeometry;
}
TemporaryRef<ID2D1RenderTarget>
DrawTargetD2D::CreateRTForTexture(ID3D10Texture2D *aTexture)
{

Просмотреть файл

@ -79,7 +79,8 @@ public:
const Point &aDest,
const Color &aColor,
const Point &aOffset,
Float aSigma);
Float aSigma,
CompositionOp aOperator);
virtual void ClearRect(const Rect &aRect);
virtual void CopySurface(SourceSurface *aSurface,
@ -159,6 +160,7 @@ private:
void PopAllClips();
TemporaryRef<ID2D1RenderTarget> CreateRTForTexture(ID3D10Texture2D *aTexture);
TemporaryRef<ID2D1Geometry> GetClippedGeometry();
TemporaryRef<ID2D1Brush> CreateBrushForPattern(const Pattern &aPattern, Float aAlpha = 1.0f);
TemporaryRef<ID2D1StrokeStyle> CreateStrokeStyleForOptions(const StrokeOptions &aStrokeOptions);

Просмотреть файл

@ -13,6 +13,7 @@ cbuffer cb0
{
float4 QuadDesc;
float4 TexCoords;
float4 MaskTexCoords;
}
cbuffer cb1
@ -27,9 +28,11 @@ struct VS_OUTPUT
{
float4 Position : SV_Position;
float2 TexCoord : TEXCOORD0;
float2 MaskTexCoord : TEXCOORD1;
};
Texture2D tex;
Texture2D mask;
sampler sSampler = sampler_state {
Filter = MIN_MAG_MIP_LINEAR;
@ -38,6 +41,13 @@ sampler sSampler = sampler_state {
AddressV = Clamp;
};
sampler sMaskSampler = sampler_state {
Filter = MIN_MAG_MIP_LINEAR;
Texture = mask;
AddressU = Clamp;
AddressV = Clamp;
};
sampler sShadowSampler = sampler_state {
Filter = MIN_MAG_MIP_LINEAR;
Texture = tex;
@ -79,6 +89,8 @@ VS_OUTPUT SampleTextureVS(float3 pos : POSITION)
Output.Position.z = 0;
Output.TexCoord.x = pos.x * TexCoords.z + TexCoords.x;
Output.TexCoord.y = pos.y * TexCoords.w + TexCoords.y;
Output.MaskTexCoord.x = pos.x * MaskTexCoords.z + MaskTexCoords.x;
Output.MaskTexCoord.y = pos.y * MaskTexCoords.w + MaskTexCoords.y;
return Output;
}
@ -87,6 +99,11 @@ float4 SampleTexturePS( VS_OUTPUT In) : SV_Target
return tex.Sample(sSampler, In.TexCoord);
};
float4 SampleMaskTexturePS( VS_OUTPUT In) : SV_Target
{
return tex.Sample(sSampler, In.TexCoord) * mask.Sample(sMaskSampler, In.MaskTexCoord).a;
};
float4 SampleShadowHPS( VS_OUTPUT In) : SV_Target
{
float outputStrength = 0;
@ -121,6 +138,23 @@ float4 SampleShadowVPS( VS_OUTPUT In) : SV_Target
return outputColor;
};
float4 SampleMaskShadowVPS( VS_OUTPUT In) : SV_Target
{
float4 outputColor = float4(0, 0, 0, 0);
outputColor += BlurWeights[0].x * tex.Sample(sShadowSampler, float2(In.TexCoord.x, In.TexCoord.y + BlurOffsetsV[0].x));
outputColor += BlurWeights[0].y * tex.Sample(sShadowSampler, float2(In.TexCoord.x, In.TexCoord.y + BlurOffsetsV[0].y));
outputColor += BlurWeights[0].z * tex.Sample(sShadowSampler, float2(In.TexCoord.x, In.TexCoord.y + BlurOffsetsV[0].z));
outputColor += BlurWeights[0].w * tex.Sample(sShadowSampler, float2(In.TexCoord.x, In.TexCoord.y + BlurOffsetsV[0].w));
outputColor += BlurWeights[1].x * tex.Sample(sShadowSampler, float2(In.TexCoord.x, In.TexCoord.y + BlurOffsetsV[1].x));
outputColor += BlurWeights[1].y * tex.Sample(sShadowSampler, float2(In.TexCoord.x, In.TexCoord.y + BlurOffsetsV[1].y));
outputColor += BlurWeights[1].z * tex.Sample(sShadowSampler, float2(In.TexCoord.x, In.TexCoord.y + BlurOffsetsV[1].z));
outputColor += BlurWeights[1].w * tex.Sample(sShadowSampler, float2(In.TexCoord.x, In.TexCoord.y + BlurOffsetsV[1].w));
outputColor += BlurWeights[2].x * tex.Sample(sShadowSampler, float2(In.TexCoord.x, In.TexCoord.y + BlurOffsetsV[2].x));
return outputColor * mask.Sample(sMaskSampler, In.MaskTexCoord).a;
};
technique10 SampleTexture
{
pass P0
@ -132,6 +166,16 @@ technique10 SampleTexture
}
}
technique10 SampleMaskedTexture
{
pass P0
{
SetRasterizerState(TextureRast);
SetVertexShader(CompileShader(vs_4_0_level_9_3, SampleTextureVS()));
SetGeometryShader(NULL);
SetPixelShader(CompileShader(ps_4_0_level_9_3, SampleMaskTexturePS()));
}
}
technique10 SampleTextureWithShadow
{
@ -153,4 +197,13 @@ technique10 SampleTextureWithShadow
SetGeometryShader(NULL);
SetPixelShader(CompileShader(ps_4_0_level_9_3, SampleShadowVPS()));
}
}
// Vertical pass - used when using a mask
pass P2
{
SetRasterizerState(TextureRast);
SetBlendState(ShadowBlendV, float4(1.0f, 1.0f, 1.0f, 1.0f), 0xffffffff);
SetVertexShader(CompileShader(vs_4_0_level_9_3, SampleTextureVS()));
SetGeometryShader(NULL);
SetPixelShader(CompileShader(ps_4_0_level_9_3, SampleMaskShadowVPS()));
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -16,12 +16,13 @@ namespace mozilla {
namespace gfx {
# if defined(MOZILLA_MAY_SUPPORT_NEON)
void __attribute((noinline)) yuv42x_to_rgb565_row_neon(uint16 *dst,
const uint8 *y,
const uint8 *u,
const uint8 *v,
int n,
int oddflag)
void __attribute((noinline,optimize("-fomit-frame-pointer")))
yuv42x_to_rgb565_row_neon(uint16 *dst,
const uint8 *y,
const uint8 *u,
const uint8 *v,
int n,
int oddflag)
{
static __attribute__((aligned(16))) uint16 acc_r[8] = {
22840, 22840, 22840, 22840, 22840, 22840, 22840, 22840,

Просмотреть файл

@ -174,6 +174,7 @@ XPC_MSG_DEF(NS_ERROR_NO_CONTENT , "Channel opened successful
XPC_MSG_DEF(NS_ERROR_IN_PROGRESS , "The requested action could not be completed while the object is busy")
XPC_MSG_DEF(NS_ERROR_ALREADY_OPENED , "Channel is already open")
XPC_MSG_DEF(NS_ERROR_INVALID_CONTENT_ENCODING , "The content encoding of the source document is incorrect")
XPC_MSG_DEF(NS_ERROR_CORRUPTED_CONTENT , "Corrupted content was received from server")
XPC_MSG_DEF(NS_ERROR_ALREADY_CONNECTED , "The connection is already established")
XPC_MSG_DEF(NS_ERROR_NOT_CONNECTED , "The connection does not exist")
XPC_MSG_DEF(NS_ERROR_CONNECTION_REFUSED , "The connection was refused")
@ -187,12 +188,15 @@ XPC_MSG_DEF(NS_ERROR_NOT_RESUMABLE , "This request is not resum
XPC_MSG_DEF(NS_ERROR_ENTITY_CHANGED , "It was attempted to resume the request, but the entity has changed in the meantime")
XPC_MSG_DEF(NS_ERROR_REDIRECT_LOOP , "The request failed as a result of a detected redirection loop")
XPC_MSG_DEF(NS_ERROR_UNSAFE_CONTENT_TYPE , "The request failed because the content type returned by the server was not a type expected by the channel")
XPC_MSG_DEF(NS_ERROR_REMOTE_XUL , "Attempt to access remote XUL document that is not in website's whitelist")
XPC_MSG_DEF(NS_ERROR_FTP_LOGIN , "FTP error while logging in")
XPC_MSG_DEF(NS_ERROR_FTP_CWD , "FTP error while changing directory")
XPC_MSG_DEF(NS_ERROR_FTP_PASV , "FTP error while changing to passive mode")
XPC_MSG_DEF(NS_ERROR_FTP_PWD , "FTP error while retrieving current directory")
XPC_MSG_DEF(NS_ERROR_FTP_LIST , "FTP error while retrieving a directory listing")
XPC_MSG_DEF(NS_ERROR_UNKNOWN_HOST , "The lookup of the hostname failed")
XPC_MSG_DEF(NS_ERROR_DNS_LOOKUP_QUEUE_FULL , "The DNS lookup queue is full")
XPC_MSG_DEF(NS_ERROR_UNKNOWN_PROXY_HOST , "The lookup of the proxy hostname failed")
XPC_MSG_DEF(NS_ERROR_UNKNOWN_SOCKET_TYPE , "The specified socket type does not exist")
XPC_MSG_DEF(NS_ERROR_SOCKET_CREATE_FAILED , "The specified socket type could not be created")

Просмотреть файл

@ -66,6 +66,7 @@ HttpChannelParent::HttpChannelParent(PBrowserParent* iframeEmbedding)
, mStoredStatus(0)
, mStoredProgress(0)
, mStoredProgressMax(0)
, mHeadersToSyncToChild(nsnull)
{
// Ensure gHttpHandler is initialized: we need the atom table up and running.
nsIHttpProtocolHandler* handler;
@ -93,13 +94,14 @@ HttpChannelParent::ActorDestroy(ActorDestroyReason why)
// HttpChannelParent::nsISupports
//-----------------------------------------------------------------------------
NS_IMPL_ISUPPORTS6(HttpChannelParent,
NS_IMPL_ISUPPORTS7(HttpChannelParent,
nsIInterfaceRequestor,
nsIProgressEventSink,
nsIRequestObserver,
nsIStreamListener,
nsIParentChannel,
nsIParentRedirectingChannel)
nsIParentRedirectingChannel,
nsIHttpHeaderVisitor)
//-----------------------------------------------------------------------------
// HttpChannelParent::nsIInterfaceRequestor
@ -425,15 +427,11 @@ HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
NS_SerializeToString(secInfoSer, secInfoSerialization);
}
// sync request headers to child, in case they've changed
RequestHeaderTuples headers;
nsHttpHeaderArray harray = requestHead->Headers();
for (PRUint32 i = 0; i < harray.Count(); i++) {
RequestHeaderTuple* tuple = headers.AppendElement();
tuple->mHeader = harray.Headers()[i].header;
tuple->mValue = harray.Headers()[i].value;
tuple->mMerge = false;
}
mHeadersToSyncToChild = &headers;
requestHead->Headers().VisitHeaders(this);
mHeadersToSyncToChild = 0;
nsHttpChannel *httpChan = static_cast<nsHttpChannel *>(mChannel.get());
if (mIPCClosed ||
@ -598,4 +596,21 @@ HttpChannelParent::CompleteRedirect(PRBool succeeded)
return NS_OK;
}
//-----------------------------------------------------------------------------
// HttpChannelParent::nsIHttpHeaderVisitor
//-----------------------------------------------------------------------------
nsresult
HttpChannelParent::VisitHeader(const nsACString &header, const nsACString &value)
{
// Will be set unless some random code QI's us to nsIHttpHeaderVisitor
NS_ENSURE_STATE(mHeadersToSyncToChild);
RequestHeaderTuple* tuple = mHeadersToSyncToChild->AppendElement();
tuple->mHeader = header;
tuple->mValue = value;
tuple->mMerge = false; // headers already merged:
return NS_OK;
}
}} // mozilla::net

Просмотреть файл

@ -63,6 +63,7 @@ class HttpChannelParent : public PHttpChannelParent
, public nsIParentRedirectingChannel
, public nsIProgressEventSink
, public nsIInterfaceRequestor
, public nsIHttpHeaderVisitor
{
public:
NS_DECL_ISUPPORTS
@ -72,6 +73,7 @@ public:
NS_DECL_NSIPARENTREDIRECTINGCHANNEL
NS_DECL_NSIPROGRESSEVENTSINK
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSIHTTPHEADERVISITOR
HttpChannelParent(PBrowserParent* iframeEmbedding);
virtual ~HttpChannelParent();
@ -130,6 +132,9 @@ private:
nsresult mStoredStatus;
PRUint64 mStoredProgress;
PRUint64 mStoredProgressMax;
// used while visiting headers, to send them to child: else null
RequestHeaderTuples *mHeadersToSyncToChild;
};
} // namespace net

Просмотреть файл

@ -83,9 +83,9 @@ struct ParamTraits<mozilla::net::RequestHeaderTuple>
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
if (!ReadParam(aMsg, aIter, &(aResult->mHeader)) ||
!ReadParam(aMsg, aIter, &(aResult->mValue)) ||
!ReadParam(aMsg, aIter, &(aResult->mMerge)))
if (!ReadParam(aMsg, aIter, &aResult->mHeader) ||
!ReadParam(aMsg, aIter, &aResult->mValue) ||
!ReadParam(aMsg, aIter, &aResult->mMerge))
return false;
return true;
@ -130,8 +130,8 @@ struct ParamTraits<nsHttpHeaderArray::nsEntry>
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
if (!ReadParam(aMsg, aIter, &(aResult->header)) ||
!ReadParam(aMsg, aIter, &(aResult->value)))
if (!ReadParam(aMsg, aIter, &aResult->header) ||
!ReadParam(aMsg, aIter, &aResult->value))
return false;
return true;
@ -147,12 +147,12 @@ struct ParamTraits<nsHttpHeaderArray>
{
paramType& p = const_cast<paramType&>(aParam);
WriteParam(aMsg, p.Headers());
WriteParam(aMsg, p.mHeaders);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
if (!ReadParam(aMsg, aIter, &(aResult->Headers())))
if (!ReadParam(aMsg, aIter, &aResult->mHeaders))
return false;
return true;
@ -180,16 +180,16 @@ struct ParamTraits<nsHttpResponseHead>
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
if (!ReadParam(aMsg, aIter, &(aResult->mHeaders)) ||
!ReadParam(aMsg, aIter, &(aResult->mVersion)) ||
!ReadParam(aMsg, aIter, &(aResult->mStatus)) ||
!ReadParam(aMsg, aIter, &(aResult->mStatusText)) ||
!ReadParam(aMsg, aIter, &(aResult->mContentLength)) ||
!ReadParam(aMsg, aIter, &(aResult->mContentType)) ||
!ReadParam(aMsg, aIter, &(aResult->mContentCharset)) ||
!ReadParam(aMsg, aIter, &(aResult->mCacheControlNoStore)) ||
!ReadParam(aMsg, aIter, &(aResult->mCacheControlNoCache)) ||
!ReadParam(aMsg, aIter, &(aResult->mPragmaNoCache)))
if (!ReadParam(aMsg, aIter, &aResult->mHeaders) ||
!ReadParam(aMsg, aIter, &aResult->mVersion) ||
!ReadParam(aMsg, aIter, &aResult->mStatus) ||
!ReadParam(aMsg, aIter, &aResult->mStatusText) ||
!ReadParam(aMsg, aIter, &aResult->mContentLength) ||
!ReadParam(aMsg, aIter, &aResult->mContentType) ||
!ReadParam(aMsg, aIter, &aResult->mContentCharset) ||
!ReadParam(aMsg, aIter, &aResult->mCacheControlNoStore) ||
!ReadParam(aMsg, aIter, &aResult->mCacheControlNoCache) ||
!ReadParam(aMsg, aIter, &aResult->mPragmaNoCache))
return false;
return true;

Просмотреть файл

@ -137,10 +137,7 @@ nsHttpChunkedDecoder::ParseChunkRemaining(char *buf,
LOG(("got trailer: %s\n", buf));
// allocate a header array for the trailers on demand
if (!mTrailers) {
mTrailers = new nsHttpHeaderArray
(nsHttpHeaderArray::HTTP_RESPONSE_HEADERS);
if (!mTrailers)
return NS_ERROR_OUT_OF_MEMORY;
mTrailers = new nsHttpHeaderArray();
}
mTrailers->ParseHeaderLine(buf);
}

Просмотреть файл

@ -22,6 +22,8 @@
*
* Contributor(s):
* Darin Fisher <darin@netscape.com> (original author)
* Patrick McManus <mcmanus@ducksong.com>
* Jason Duell <jduell.mcbugs@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -43,7 +45,6 @@
//-----------------------------------------------------------------------------
// nsHttpHeaderArray <public>
//-----------------------------------------------------------------------------
nsresult
nsHttpHeaderArray::SetHeader(nsHttpAtom header,
const nsACString &value,
@ -62,33 +63,50 @@ nsHttpHeaderArray::SetHeader(nsHttpAtom header,
return NS_OK;
}
// Create a new entry, or...
if (!entry) {
entry = mHeaders.AppendElement(); // new nsEntry()
if (!entry)
return NS_ERROR_OUT_OF_MEMORY;
entry->header = header;
entry->value = value;
} else if (merge && !IsSingletonHeader(header)) {
MergeHeader(header, entry, value);
} else {
// Replace the existing string with the new value
entry->value = value;
}
return NS_OK;
}
nsresult
nsHttpHeaderArray::SetHeaderFromNet(nsHttpAtom header, const nsACString &value)
{
nsEntry *entry = nsnull;
PRInt32 index;
index = LookupEntry(header, &entry);
if (!entry) {
if (value.IsEmpty())
return NS_OK; // ignore empty headers
entry = mHeaders.AppendElement(); //new nsEntry(header, value);
if (!entry)
return NS_ERROR_OUT_OF_MEMORY;
entry->header = header;
entry->value = value;
} else if (!IsSingletonHeader(header)) {
MergeHeader(header, entry, value);
} else {
// Multiple instances of non-mergeable header received from network
// - ignore if same value
if (!entry->value.Equals(value)) {
if (IsSuspectDuplicateHeader(header)) {
// reply may be corrupt/hacked (ex: CLRF injection attacks)
return NS_ERROR_CORRUPTED_CONTENT;
} // else silently drop value: keep value from 1st header seen
}
}
// Append the new value to the existing value iff...
else if (merge && CanAppendToHeader(header)) {
if (header == nsHttp::Set_Cookie ||
header == nsHttp::WWW_Authenticate ||
header == nsHttp::Proxy_Authenticate)
// Special case these headers and use a newline delimiter to
// delimit the values from one another as commas may appear
// in the values of these headers contrary to what the spec says.
entry->value.Append('\n');
else
// Delimit each value from the others using a comma (per HTTP spec)
entry->value.AppendLiteral(", ");
entry->value.Append(value);
}
// Replace the existing string with the new value
else if (CanOverwriteHeader(header))
entry->value = value;
else if (!entry->value.Equals(value))
return NS_ERROR_CORRUPTED_CONTENT;
return NS_OK;
}
@ -186,7 +204,7 @@ nsHttpHeaderArray::ParseHeaderLine(const char *line,
if (val) *val = p;
// assign response header
return SetHeader(atom, nsDependentCString(p, p2 - p), PR_TRUE);
return SetHeaderFromNet(atom, nsDependentCString(p, p2 - p));
}
void
@ -220,41 +238,3 @@ nsHttpHeaderArray::Clear()
{
mHeaders.Clear();
}
//-----------------------------------------------------------------------------
// nsHttpHeaderArray <private>
//-----------------------------------------------------------------------------
PRInt32
nsHttpHeaderArray::LookupEntry(nsHttpAtom header, nsEntry **entry)
{
PRUint32 index = mHeaders.IndexOf(header, 0, nsEntry::MatchHeader());
if (index != PR_UINT32_MAX)
*entry = &mHeaders[index];
return index;
}
PRBool
nsHttpHeaderArray::CanAppendToHeader(nsHttpAtom header)
{
return header != nsHttp::Content_Type &&
header != nsHttp::Content_Length &&
header != nsHttp::User_Agent &&
header != nsHttp::Referer &&
header != nsHttp::Host &&
header != nsHttp::Authorization &&
header != nsHttp::Proxy_Authorization &&
header != nsHttp::If_Modified_Since &&
header != nsHttp::If_Unmodified_Since &&
header != nsHttp::From &&
header != nsHttp::Location &&
header != nsHttp::Max_Forwards;
}
PRBool
nsHttpHeaderArray::CanOverwriteHeader(nsHttpAtom header)
{
if (mType != HTTP_RESPONSE_HEADERS)
return PR_TRUE;
return header != nsHttp::Content_Length;
}

Просмотреть файл

@ -1,4 +1,5 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -49,17 +50,19 @@
class nsHttpHeaderArray
{
public:
enum nsHttpHeaderType {
HTTP_REQUEST_HEADERS,
HTTP_RESPONSE_HEADERS
};
nsHttpHeaderArray(nsHttpHeaderType headerType) : mType(headerType) {}
nsHttpHeaderArray() {}
~nsHttpHeaderArray() { Clear(); }
const char *PeekHeader(nsHttpAtom header);
nsresult SetHeader(nsHttpAtom header, const nsACString &value, PRBool merge = PR_FALSE);
// Used by internal setters: to set header from network use SetHeaderFromNet
nsresult SetHeader(nsHttpAtom header, const nsACString &value,
PRBool merge = PR_FALSE);
// Merges supported headers. For other duplicate values, determines if error
// needs to be thrown or 1st value kept.
nsresult SetHeaderFromNet(nsHttpAtom header, const nsACString &value);
nsresult GetHeader(nsHttpAtom header, nsACString &value);
void ClearHeader(nsHttpAtom h);
@ -104,15 +107,90 @@ public:
};
};
nsTArray<nsEntry> &Headers() { return mHeaders; }
private:
PRInt32 LookupEntry(nsHttpAtom header, nsEntry **);
PRBool CanAppendToHeader(nsHttpAtom header);
PRBool CanOverwriteHeader(nsHttpAtom header);
void MergeHeader(nsHttpAtom header, nsEntry *entry, const nsACString &value);
// Header cannot be merged: only one value possible
PRBool IsSingletonHeader(nsHttpAtom header);
// Subset of singleton headers: should never see multiple, different
// instances of these, else something fishy may be going on (like CLRF
// injection)
PRBool IsSuspectDuplicateHeader(nsHttpAtom header);
nsTArray<nsEntry> mHeaders;
nsHttpHeaderType mType;
friend struct IPC::ParamTraits<nsHttpHeaderArray>;
};
//-----------------------------------------------------------------------------
// nsHttpHeaderArray <private>: inline functions
//-----------------------------------------------------------------------------
inline PRInt32
nsHttpHeaderArray::LookupEntry(nsHttpAtom header, nsEntry **entry)
{
PRUint32 index = mHeaders.IndexOf(header, 0, nsEntry::MatchHeader());
if (index != PR_UINT32_MAX)
*entry = &mHeaders[index];
return index;
}
inline PRBool
nsHttpHeaderArray::IsSingletonHeader(nsHttpAtom header)
{
return header == nsHttp::Content_Type ||
header == nsHttp::Content_Disposition ||
header == nsHttp::Content_Length ||
header == nsHttp::User_Agent ||
header == nsHttp::Referer ||
header == nsHttp::Host ||
header == nsHttp::Authorization ||
header == nsHttp::Proxy_Authorization ||
header == nsHttp::If_Modified_Since ||
header == nsHttp::If_Unmodified_Since ||
header == nsHttp::From ||
header == nsHttp::Location ||
header == nsHttp::Max_Forwards;
}
inline void
nsHttpHeaderArray::MergeHeader(nsHttpAtom header,
nsEntry *entry,
const nsACString &value)
{
if (value.IsEmpty())
return; // merge of empty header = no-op
// Append the new value to the existing value
if (header == nsHttp::Set_Cookie ||
header == nsHttp::WWW_Authenticate ||
header == nsHttp::Proxy_Authenticate)
{
// Special case these headers and use a newline delimiter to
// delimit the values from one another as commas may appear
// in the values of these headers contrary to what the spec says.
entry->value.Append('\n');
} else {
// Delimit each value from the others using a comma (per HTTP spec)
entry->value.AppendLiteral(", ");
}
entry->value.Append(value);
}
inline PRBool
nsHttpHeaderArray::IsSuspectDuplicateHeader(nsHttpAtom header)
{
PRBool retval = header == nsHttp::Content_Length ||
header == nsHttp::Content_Disposition ||
header == nsHttp::Location;
NS_ASSERTION(!retval || IsSingletonHeader(header),
"Only non-mergeable headers should be in this list\n");
return retval;
}
#endif

Просмотреть файл

@ -52,9 +52,7 @@
class nsHttpRequestHead
{
public:
nsHttpRequestHead() : mHeaders(nsHttpHeaderArray::HTTP_REQUEST_HEADERS)
, mMethod(nsHttp::Get)
, mVersion(NS_HTTP_VERSION_1_1) {}
nsHttpRequestHead() : mMethod(nsHttp::Get), mVersion(NS_HTTP_VERSION_1_1) {}
~nsHttpRequestHead() {}
void SetMethod(nsHttpAtom method) { mMethod = method; }

Просмотреть файл

@ -445,7 +445,6 @@ nsHttpResponseHead::UpdateHeaders(nsHttpHeaderArray &headers)
const char *val = headers.PeekHeaderAt(i, header);
if (!val) {
NS_NOTREACHED("null header value");
continue;
}

Просмотреть файл

@ -51,8 +51,7 @@
class nsHttpResponseHead
{
public:
nsHttpResponseHead() : mHeaders(nsHttpHeaderArray::HTTP_RESPONSE_HEADERS)
, mVersion(NS_HTTP_VERSION_1_1)
nsHttpResponseHead() : mVersion(NS_HTTP_VERSION_1_1)
, mStatus(200)
, mContentLength(LL_MAXUINT)
, mCacheControlNoStore(PR_FALSE)

Просмотреть файл

@ -1,43 +0,0 @@
do_load_httpd_js();
var httpserver = new nsHttpServer();
var index = 0;
function setupChannel(url)
{
var ios = Components.classes["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
var chan = ios.newChannel("http://localhost:4444" + url, "", null);
var httpChan = chan.QueryInterface(Components.interfaces.nsIHttpChannel);
return httpChan;
}
function completeTest1(request, data, ctx)
{
httpserver.stop(do_test_finished);
}
function run_test()
{
httpserver.registerPathHandler("/2xcl", handler);
httpserver.start(4444);
var channel = setupChannel("/2xcl");
channel.asyncOpen(new ChannelListener(completeTest1,
channel, CL_EXPECT_FAILURE), null);
do_test_pending();
}
function handler(metadata, response)
{
var body = "012345678901234567890123456789";
response.seizePower();
response.write("HTTP/1.0 200 OK\r\n");
response.write("Content-Type: text/plain\r\n");
response.write("Content-Length: 20\r\n");
response.write("Content-Length: 30\r\n");
response.write("\r\n");
response.write(body);
response.finish();
}

Просмотреть файл

@ -0,0 +1,363 @@
/*
* Tests bugs 597706, 655389: prevent duplicate headers with differing values
* for some headers like Content-Length, Location, etc.
*/
////////////////////////////////////////////////////////////////////////////////
// Test infrastructure
do_load_httpd_js();
var httpserver = new nsHttpServer();
var index = 0;
var test_flags = new Array();
var testPathBase = "/dupe_hdrs";
function run_test()
{
httpserver.start(4444);
do_test_pending();
run_test_number(1);
}
function run_test_number(num)
{
testPath = testPathBase + num;
httpserver.registerPathHandler(testPath, eval("handler" + num));
var channel = setupChannel(testPath);
flags = test_flags[num]; // OK if flags undefined for test
channel.asyncOpen(new ChannelListener(eval("completeTest" + num),
channel, flags), null);
}
function setupChannel(url)
{
var ios = Components.classes["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
var chan = ios.newChannel("http://localhost:4444" + url, "", null);
var httpChan = chan.QueryInterface(Components.interfaces.nsIHttpChannel);
return httpChan;
}
function endTests()
{
httpserver.stop(do_test_finished);
}
////////////////////////////////////////////////////////////////////////////////
// Test 1: FAIL because of conflicting Content-Length headers
test_flags[1] = CL_EXPECT_FAILURE;
function handler1(metadata, response)
{
var body = "012345678901234567890123456789";
// Comrades! We must seize power from the petty-bourgeois running dogs of
// httpd.js in order to reply with multiple instances of the same header!
response.seizePower();
response.write("HTTP/1.0 200 OK\r\n");
response.write("Content-Type: text/plain\r\n");
response.write("Content-Length: 30\r\n");
response.write("Content-Length: 20\r\n");
response.write("\r\n");
response.write(body);
response.finish();
}
function completeTest1(request, data, ctx)
{
do_check_eq(request.status, Components.results.NS_ERROR_CORRUPTED_CONTENT);
run_test_number(2);
}
////////////////////////////////////////////////////////////////////////////////
// Test 2: OK to have duplicate same Content-Length headers
function handler2(metadata, response)
{
var body = "012345678901234567890123456789";
response.seizePower();
response.write("HTTP/1.0 200 OK\r\n");
response.write("Content-Type: text/plain\r\n");
response.write("Content-Length: 30\r\n");
response.write("Content-Length: 30\r\n");
response.write("\r\n");
response.write(body);
response.finish();
}
function completeTest2(request, data, ctx)
{
do_check_eq(request.status, 0);
run_test_number(3);
}
////////////////////////////////////////////////////////////////////////////////
// Test 3: FAIL: 2nd Content-length is blank
test_flags[3] = CL_EXPECT_FAILURE;
function handler3(metadata, response)
{
var body = "012345678901234567890123456789";
response.seizePower();
response.write("HTTP/1.0 200 OK\r\n");
response.write("Content-Type: text/plain\r\n");
response.write("Content-Length: 30\r\n");
response.write("Content-Length:\r\n");
response.write("\r\n");
response.write(body);
response.finish();
}
function completeTest3(request, data, ctx)
{
do_check_eq(request.status, Components.results.NS_ERROR_CORRUPTED_CONTENT);
run_test_number(4);
}
////////////////////////////////////////////////////////////////////////////////
// Test 4: ensure that blank C-len header doesn't allow attacker to reset Clen,
// then insert CRLF attack
test_flags[4] = CL_EXPECT_FAILURE;
function handler4(metadata, response)
{
var body = "012345678901234567890123456789";
response.seizePower();
response.write("HTTP/1.0 200 OK\r\n");
response.write("Content-Type: text/plain\r\n");
response.write("Content-Length: 30\r\n");
// Bad Mr Hacker! Bad!
var evilBody = "We are the Evil bytes, Evil bytes, Evil bytes!";
response.write("Content-Length:\r\n");
response.write("Content-Length: %s\r\n\r\n%s" % (evilBody.length, evilBody));
response.write("\r\n");
response.write(body);
response.finish();
}
function completeTest4(request, data, ctx)
{
do_check_eq(request.status, Components.results.NS_ERROR_CORRUPTED_CONTENT);
run_test_number(5);
}
////////////////////////////////////////////////////////////////////////////////
// Test 5: ensure that we take 1st instance of duplicate, nonmerged headers that
// are permitted : (ex: Referrer)
function handler5(metadata, response)
{
var body = "012345678901234567890123456789";
response.seizePower();
response.write("HTTP/1.0 200 OK\r\n");
response.write("Content-Type: text/plain\r\n");
response.write("Content-Length: 30\r\n");
response.write("Referer: naive.org\r\n");
response.write("Referer: evil.net\r\n");
response.write("\r\n");
response.write(body);
response.finish();
}
function completeTest5(request, data, ctx)
{
try {
referer = request.getResponseHeader("Referer");
do_check_eq(referer, "naive.org");
} catch (ex) {
do_throw("Referer header should be present");
}
run_test_number(6);
}
////////////////////////////////////////////////////////////////////////////////
// Test 5: FAIL if multiple, different Location: headers present
// - needed to prevent CRLF injection attacks
test_flags[6] = CL_EXPECT_FAILURE;
function handler6(metadata, response)
{
var body = "012345678901234567890123456789";
response.seizePower();
response.write("HTTP/1.0 301 Moved\r\n");
response.write("Content-Type: text/plain\r\n");
response.write("Content-Length: 30\r\n");
response.write("Location: http://localhost:4444/content\r\n");
response.write("Location: http://www.microsoft.com/\r\n");
response.write("Connection: close/\r\n");
response.write("\r\n");
response.write(body);
response.finish();
}
function completeTest6(request, data, ctx)
{
do_check_eq(request.status, Components.results.NS_ERROR_CORRUPTED_CONTENT);
// run_test_number(7); // Test 7 leaking under e10s: unrelated bug?
run_test_number(8);
}
////////////////////////////////////////////////////////////////////////////////
// Test 7: OK to have multiple Location: headers with same value
function handler7(metadata, response)
{
var body = "012345678901234567890123456789";
response.seizePower();
response.write("HTTP/1.0 301 Moved\r\n");
response.write("Content-Type: text/plain\r\n");
response.write("Content-Length: 30\r\n");
// redirect to previous test handler that completes OK: test 5
response.write("Location: http://localhost:4444" + testPathBase + "5\r\n");
response.write("Location: http://localhost:4444" + testPathBase + "5\r\n");
response.write("Connection: close/\r\n");
response.write("\r\n");
response.write(body);
response.finish();
}
function completeTest7(request, data, ctx)
{
// for some reason need this here
request.QueryInterface(Components.interfaces.nsIHttpChannel);
try {
referer = request.getResponseHeader("Referer");
do_check_eq(referer, "naive.org");
} catch (ex) {
do_throw("Referer header should be present");
}
run_test_number(8);
}
////////////////////////////////////////////////////////////////////////////////
// FAIL if 2nd Location: headers blank
test_flags[8] = CL_EXPECT_FAILURE;
function handler8(metadata, response)
{
var body = "012345678901234567890123456789";
response.seizePower();
response.write("HTTP/1.0 301 Moved\r\n");
response.write("Content-Type: text/plain\r\n");
response.write("Content-Length: 30\r\n");
// redirect to previous test handler that completes OK: test 4
response.write("Location: http://localhost:4444" + testPathBase + "4\r\n");
response.write("Location:\r\n");
response.write("Connection: close/\r\n");
response.write("\r\n");
response.write(body);
response.finish();
}
function completeTest8(request, data, ctx)
{
do_check_eq(request.status, Components.results.NS_ERROR_CORRUPTED_CONTENT);
run_test_number(9);
}
////////////////////////////////////////////////////////////////////////////////
// Test 9: ensure that blank Location header doesn't allow attacker to reset,
// then insert an evil one
test_flags[9] = CL_EXPECT_FAILURE;
function handler9(metadata, response)
{
var body = "012345678901234567890123456789";
response.seizePower();
response.write("HTTP/1.0 301 Moved\r\n");
response.write("Content-Type: text/plain\r\n");
response.write("Content-Length: 30\r\n");
// redirect to previous test handler that completes OK: test 2
response.write("Location: http://localhost:4444" + testPathBase + "2\r\n");
response.write("Location:\r\n");
// redirect to previous test handler that completes OK: test 4
response.write("Location: http://localhost:4444" + testPathBase + "4\r\n");
response.write("Connection: close/\r\n");
response.write("\r\n");
response.write(body);
response.finish();
}
function completeTest9(request, data, ctx)
{
// All redirection should fail:
do_check_eq(request.status, Components.results.NS_ERROR_CORRUPTED_CONTENT);
run_test_number(10);
}
////////////////////////////////////////////////////////////////////////////////
// Test 10: FAIL: if conflicting values for Content-Dispo
test_flags[10] = CL_EXPECT_FAILURE;
function handler10(metadata, response)
{
var body = "012345678901234567890123456789";
response.seizePower();
response.write("HTTP/1.0 200 OK\r\n");
response.write("Content-Type: text/plain\r\n");
response.write("Content-Length: 30\r\n");
response.write("Content-Disposition: attachment; filename=foo\r\n");
response.write("Content-Disposition: attachment; filename=bar\r\n");
response.write("Content-Disposition: attachment; filename=baz\r\n");
response.write("\r\n");
response.write(body);
response.finish();
}
function completeTest10(request, data, ctx)
{
do_check_eq(request.status, Components.results.NS_ERROR_CORRUPTED_CONTENT);
run_test_number(11);
}
////////////////////////////////////////////////////////////////////////////////
// Test 11: OK to have duplicate same Content-Disposition headers
function handler11(metadata, response)
{
var body = "012345678901234567890123456789";
response.seizePower();
response.write("HTTP/1.0 200 OK\r\n");
response.write("Content-Type: text/plain\r\n");
response.write("Content-Length: 30\r\n");
response.write("Content-Disposition: attachment; filename=foo\r\n");
response.write("Content-Disposition: attachment; filename=foo\r\n");
response.write("\r\n");
response.write(body);
response.finish();
}
function completeTest11(request, data, ctx)
{
do_check_eq(request.status, 0);
try {
// TODO when bug XXX lands, also get channel C-D properties and make sure
// they're blank
dispo = request.getResponseHeader("Content-Disposition");
do_check_eq(dispo, "attachment; filename=foo");
} catch (ex) {
do_throw("Content-Disposition should be present");
}
endTests();
}

Просмотреть файл

@ -74,7 +74,7 @@ tail =
[test_cookie_header.js]
[test_data_protocol.js]
[test_dns_service.js]
[test_double_content_length.js]
[test_duplicate_headers.js]
[test_event_sink.js]
[test_extract_charset_from_content_type.js]
[test_fallback_no-cache-entry_canceled.js]

Просмотреть файл

@ -0,0 +1,7 @@
//
// Run test script in content process instead of chrome (xpcshell's default)
//
function run_test() {
run_test_in_child("../unit/test_duplicate_headers.js");
}

Просмотреть файл

@ -4,6 +4,7 @@ tail =
[test_channel_close_wrap.js]
[test_cookie_wrap.js]
[test_duplicate_headers_wrap.js]
[test_event_sink_wrap.js]
[test_head_wrap.js]
[test_httpcancel_wrap.js]

Просмотреть файл

@ -52,6 +52,7 @@ ifdef MOZ_THUMB2 #{
# work around it by telling gcc that the THUMB frame pointer is a
# vanilla callee-save register.
OS_CXXFLAGS += -fomit-frame-pointer
MOZ_OPTIMIZE_FLAGS := $(filter-out -fno-omit-frame-pointer,$(MOZ_OPTIMIZE_FLAGS))
endif #}
MODULE = handler