Merge autoland to mozilla-central. a=merge

This commit is contained in:
Cosmin Sabou 2018-04-02 13:15:52 +03:00
commit 121725038a
79 changed files with 3268 additions and 399 deletions

27
Cargo.lock generated
View File

@ -819,6 +819,19 @@ dependencies = [
"url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hyper_serde"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cookie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
"mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ident_case"
version = "1.0.0"
@ -966,10 +979,14 @@ dependencies = [
"cssparser 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)",
"hashglobe 0.1.0",
"hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper_serde 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"selectors 0.19.0",
"serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
"servo_arc 0.1.1",
"smallbitvec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1574,6 +1591,14 @@ dependencies = [
"serde_derive 1.0.35 (git+https://github.com/servo/serde?branch=deserialize_from_enums5)",
]
[[package]]
name = "serde_bytes"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive"
version = "1.0.35"
@ -2294,6 +2319,7 @@ dependencies = [
"checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07"
"checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e"
"checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2"
"checksum hyper_serde 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0997ad463f64ce6ba02cf5af320622bb9782e4f8355b650a2cc7ccca69a7cc2e"
"checksum ident_case 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c9826188e666f2ed92071d2dadef6edc430b11b158b5b2b3f4babbcc891eaaa"
"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
"checksum iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29d062ee61fccdf25be172e70f34c9f6efc597e1fb8f6526e8437b2046ab26be"
@ -2368,6 +2394,7 @@ dependencies = [
"checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "800fdb0a894572994f3970035a8a5f65d8ec2cd40e6cdf7d8cd9001d7b30648e"
"checksum serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "adb6e51a6b3696b301bc221d785f898b4457c619b51d7ce195a6d20baecb37b3"
"checksum serde_derive 1.0.35 (git+https://github.com/servo/serde?branch=deserialize_from_enums5)" = "<none>"
"checksum serde_derive_internals 0.22.1 (git+https://github.com/servo/serde?branch=deserialize_from_enums5)" = "<none>"
"checksum simd 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd0805c7363ab51a829a1511ad24b6ed0349feaa756c4bc2f977f9f496e6673"

View File

@ -474,6 +474,13 @@ var Policies = {
}
},
"OverrideFirstRunPage": {
onProfileAfterChange(manager, param) {
let url = param ? param.spec : "";
setAndLockPref("startup.homepage_welcome_url", url);
}
},
"PopupBlocking": {
onBeforeUIStartup(manager, param) {
addAllowDenyPermissions("popup", param.Allow, null);

View File

@ -350,6 +350,14 @@
"type": "boolean"
},
"OverrideFirstRunPage": {
"description": "Override the first run page. Set this policy to blank if you want to disable the first run page.",
"first_available": "60.0",
"enterprise_only": true,
"type": "URLorEmpty"
},
"PopupBlocking": {
"description": "Allow or deny popup usage.",
"first_available": "60.0",

View File

@ -69,6 +69,12 @@ const POLICIES_TESTS = [
"privacy.trackingprotection.pbmode.enabled": false,
}
},
// POLICY: OverrideFirstRunPage
{
policies: { "OverrideFirstRunPage": "https://www.example.com/" },
lockedPrefs: { "startup.homepage_welcome_url": "https://www.example.com/" },
},
];
add_task(async function test_policy_remember_passwords() {

View File

@ -729,7 +729,8 @@ exports.CSS_PROPERTIES = {
"column-gap"
],
"supports": [
6
6,
8
],
"values": [
"calc",
@ -2081,6 +2082,7 @@ exports.CSS_PROPERTIES = {
"-moz-min-content",
"auto",
"calc",
"content",
"inherit",
"initial",
"unset"
@ -2102,6 +2104,7 @@ exports.CSS_PROPERTIES = {
"-moz-min-content",
"auto",
"calc",
"content",
"inherit",
"initial",
"unset"
@ -5118,7 +5121,8 @@ exports.CSS_PROPERTIES = {
"column-gap"
],
"supports": [
6
6,
8
],
"values": [
"calc",
@ -5547,6 +5551,7 @@ exports.CSS_PROPERTIES = {
"-moz-min-content",
"auto",
"calc",
"content",
"inherit",
"initial",
"unset"
@ -5568,6 +5573,7 @@ exports.CSS_PROPERTIES = {
"-moz-min-content",
"auto",
"calc",
"content",
"inherit",
"initial",
"unset"

View File

@ -52,9 +52,9 @@ div {
<script>
'use strict';
function getDocShellForObservingRestyles() {
function getDocShellForObservingRestylesForWindow(aWindow) {
const docShell =
SpecialPowers.wrap(window)
SpecialPowers.wrap(aWindow)
.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
.getInterface(SpecialPowers.Ci.nsIWebNavigation)
.QueryInterface(SpecialPowers.Ci.nsIDocShell);
@ -66,16 +66,22 @@ function getDocShellForObservingRestyles() {
}
// Returns the animation restyle markers observed during |frameCount| refresh
// driver ticks. This function is typically used to count the number of
// restyles that take place as part of the style update that happens on each
// refresh driver tick, as opposed to synchronous restyles triggered by script.
// driver ticks in this `window`. This function is typically used to count the
// number of restyles that take place as part of the style update that happens
// on each refresh driver tick, as opposed to synchronous restyles triggered by
// script.
//
// For the latter observeAnimSyncStyling (below) should be used.
function observeStyling(frameCount, onFrame) {
let docShell = getDocShellForObservingRestyles();
return observeStylingInTargetWindow(window, frameCount, onFrame);
}
// As with observeStyling but applied to target window |aWindow|.
function observeStylingInTargetWindow(aWindow, aFrameCount, aOnFrame) {
let docShell = getDocShellForObservingRestylesForWindow(aWindow);
return new Promise(resolve => {
return waitForAnimationFrames(frameCount, onFrame).then(() => {
return waitForAnimationFrames(aFrameCount, aOnFrame).then(() => {
var markers = docShell.popProfileTimelineMarkers();
docShell.recordProfileTimelineMarkers = false;
var stylingMarkers = markers.filter((marker, index) => {
@ -93,7 +99,7 @@ function observeStyling(frameCount, onFrame) {
// |funcToMakeRestyleHappen|, which may be expected to trigger a synchronous
// restyles, and returns any restyle markers produced by calling that function.
function observeAnimSyncStyling(funcToMakeRestyleHappen) {
let docShell = getDocShellForObservingRestyles();
let docShell = getDocShellForObservingRestylesForWindow(window);
funcToMakeRestyleHappen();
@ -1639,6 +1645,78 @@ waitForAllPaints(() => {
}
);
add_task(
async function throttling_position_absolute_animations_in_collapsed_iframe() {
var iframe = document.createElement('iframe');
iframe.setAttribute('srcdoc', '<div id="target"></div>');
iframe.style.height = '0px';
document.documentElement.appendChild(iframe);
await new Promise(resolve => {
iframe.addEventListener('load', () => {
resolve();
});
});
const target = iframe.contentDocument.getElementById("target");
target.style= 'position: absolute; top: 50%; width: 100px; height: 100px';
var animation = target.animate({ opacity: [0, 1] },
{ duration: 100 * MS_PER_SEC,
iterations: Infinity });
await animation.ready;
var markers = await observeStylingInTargetWindow(iframe.contentWindow, 5);
is(markers.length, 0,
'Animation on position:absolute element in collapsed iframe should ' +
'be throttled');
await ensureElementRemoval(iframe);
}
);
add_task(
async function position_absolute_animations_in_collapsed_element() {
var parent = addDiv(null, { style: 'overflow: scroll; height: 0px;' });
var target = addDiv(null,
{ style: 'animation: background-color 100s infinite;' +
'position: absolute; top: 50%;' +
'width: 100px; height: 100px;' });
parent.appendChild(target);
var animation = target.getAnimations()[0];
await animation.ready;
const expectedRestyleCount = tweakExpectedRestyleCount(animation, 5);
var markers = await observeStyling(5);
is(markers.length, expectedRestyleCount,
'Animation on position:absolute element in collapsed element ' +
'should not be throttled');
await ensureElementRemoval(parent);
}
);
add_task(
async function throttling_position_absolute_animations_in_collapsed_element() {
var parent = addDiv(null, { style: 'overflow: scroll; height: 0px;' });
var target = addDiv(null,
{ style: 'animation: background-color 100s infinite;' +
'position: absolute; top: 50%;' });
parent.appendChild(target);
var animation = target.getAnimations()[0];
await animation.ready;
var markers = await observeStyling(5);
todo_is(markers.length, 0,
'Animation on collapsed position:absolute element in collapsed ' +
'element should be throttled');
await ensureElementRemoval(parent);
}
);
add_task_if_omta_enabled(
async function no_restyling_for_compositor_animation_on_unrelated_style_change() {
var div = addDiv(null);

View File

@ -10361,3 +10361,32 @@ nsLayoutUtils::ParseFontLanguageOverride(const nsAString& aLangTag)
}
return result;
}
/* static */ nscoord
nsLayoutUtils::ResolveGapToLength(const nsStyleCoord& aCoord,
nscoord aPercentageBasis)
{
switch (aCoord.GetUnit()) {
case eStyleUnit_Normal:
return nscoord(0);
case eStyleUnit_Coord:
return aCoord.GetCoordValue();
case eStyleUnit_Percent:
if (aPercentageBasis == NS_UNCONSTRAINEDSIZE) {
return nscoord(0);
}
return NSToCoordFloorClamped(aPercentageBasis *
aCoord.GetPercentValue());
case eStyleUnit_Calc: {
nsStyleCoord::Calc* calc = aCoord.GetCalcValue();
if (aPercentageBasis == NS_UNCONSTRAINEDSIZE) {
return std::max(nscoord(0), calc->mLength);
}
return std::max(nscoord(0), calc->mLength +
NSToCoordFloorClamped(aPercentageBasis * calc->mPercent));
}
default:
MOZ_ASSERT_UNREACHABLE("Unexpected unit!");
return nscoord(0);
}
}

View File

@ -3063,6 +3063,14 @@ public:
static uint32_t ParseFontLanguageOverride(const nsAString& aLangTag);
/**
* Resolve a column-gap/row-gap to a definite size.
* @note This method resolves 'normal' to zero.
* Callers who want different behavior should handle 'normal' on their own.
*/
static nscoord ResolveGapToLength(const nsStyleCoord& aGap,
nscoord aPercentageBasis);
private:
static uint32_t sFontSizeInflationEmPerLine;
static uint32_t sFontSizeInflationMinTwips;

View File

@ -289,18 +289,14 @@ nsColumnSetFrame::GetAvailableContentBSize(const ReflowInput& aReflowInput)
static nscoord
GetColumnGap(nsColumnSetFrame* aFrame,
const nsStyleColumn* aColStyle)
const nsStyleColumn* aColStyle,
nscoord aPercentageBasis)
{
if (eStyleUnit_Normal == aColStyle->mColumnGap.GetUnit())
const auto& columnGap = aColStyle->mColumnGap;
if (columnGap.GetUnit() == eStyleUnit_Normal) {
return aFrame->StyleFont()->mFont.size;
if (eStyleUnit_Coord == aColStyle->mColumnGap.GetUnit()) {
nscoord colGap = aColStyle->mColumnGap.GetCoordValue();
NS_ASSERTION(colGap >= 0, "negative column gap");
return colGap;
}
NS_NOTREACHED("Unknown gap type");
return 0;
return nsLayoutUtils::ResolveGapToLength(columnGap, aPercentageBasis);
}
nsColumnSetFrame::ReflowConfig
@ -334,7 +330,7 @@ nsColumnSetFrame::ChooseColumnStrategy(const ReflowInput& aReflowInput,
colBSize = std::min(colBSize, aReflowInput.ComputedMaxBSize());
}
nscoord colGap = GetColumnGap(this, colStyle);
nscoord colGap = GetColumnGap(this, colStyle, aReflowInput.ComputedISize());
int32_t numColumns = colStyle->mColumnCount;
// If column-fill is set to 'balance', then we want to balance the columns.
@ -518,7 +514,7 @@ nsColumnSetFrame::GetMinISize(gfxContext *aRenderingContext)
// include n-1 column gaps.
colISize = iSize;
iSize *= colStyle->mColumnCount;
nscoord colGap = GetColumnGap(this, colStyle);
nscoord colGap = GetColumnGap(this, colStyle, NS_UNCONSTRAINEDSIZE);
iSize += colGap * (colStyle->mColumnCount - 1);
// The multiplication above can make 'width' negative (integer overflow),
// so use std::max to protect against that.
@ -539,7 +535,7 @@ nsColumnSetFrame::GetPrefISize(gfxContext *aRenderingContext)
nscoord result = 0;
DISPLAY_PREF_WIDTH(this, result);
const nsStyleColumn* colStyle = StyleColumn();
nscoord colGap = GetColumnGap(this, colStyle);
nscoord colGap = GetColumnGap(this, colStyle, NS_UNCONSTRAINEDSIZE);
nscoord colISize;
if (colStyle->mColumnWidth.GetUnit() == eStyleUnit_Coord) {

View File

@ -13,6 +13,7 @@
#include "nsAbsoluteContainingBlock.h"
#include "nsAttrValue.h"
#include "nsAttrValueInlines.h"
#include "nsFlexContainerFrame.h"
#include "nsIDocument.h"
#include "nsPresContext.h"
#include "nsRect.h"
@ -846,8 +847,18 @@ nsContainerFrame::ComputeAutoSize(gfxContext* aRenderingContext,
aBorder.ISize(aWM) - aPadding.ISize(aWM);
// replaced elements always shrink-wrap
if ((aFlags & ComputeSizeFlags::eShrinkWrap) || IsFrameOfType(eReplaced)) {
// don't bother setting it if the result won't be used
if (StylePosition()->ISize(aWM).GetUnit() == eStyleUnit_Auto) {
// Only bother computing our 'auto' ISize if the result will be used.
// It'll be used under two scenarios:
// - If our ISize property is itself 'auto'.
// - If we're using flex-basis in place of our ISize property (i.e. we're a
// flex item with our inline axis being the main axis), AND we have
// flex-basis:content.
const nsStylePosition* pos = StylePosition();
if (pos->ISize(aWM).GetUnit() == eStyleUnit_Auto ||
(pos->mFlexBasis.GetUnit() == eStyleUnit_Enumerated &&
pos->mFlexBasis.GetIntValue() == NS_STYLE_FLEX_BASIS_CONTENT &&
IsFlexItem() &&
nsFlexContainerFrame::IsItemInlineAxisMainAxis(this))) {
result.ISize(aWM) = ShrinkWidthToFit(aRenderingContext, availBased, aFlags);
}
} else {

View File

@ -5674,9 +5674,22 @@ nsFrame::ComputeSize(gfxContext* aRenderingContext,
// nsFrame::ComputeSizeWithIntrinsicDimensions().
const nsStyleCoord* flexBasis = &(stylePos->mFlexBasis);
if (flexBasis->GetUnit() != eStyleUnit_Auto) {
// Override whichever styleCoord is in flex container's main axis:
(flexMainAxis == eLogicalAxisInline ?
inlineStyleCoord : blockStyleCoord) = flexBasis;
// Replace our main-axis styleCoord pointer with a different one,
// depending on our flex-basis value.
auto& mainAxisCoord = (flexMainAxis == eLogicalAxisInline
? inlineStyleCoord : blockStyleCoord);
if (flexBasis->GetUnit() == eStyleUnit_Enumerated &&
flexBasis->GetIntValue() == NS_STYLE_FLEX_BASIS_CONTENT) {
// We have 'flex-basis: content', which is equivalent to
// 'flex-basis:auto; {main-size}: auto'. So, just swap in a dummy
// 'auto' value to use for the main size property:
static const nsStyleCoord autoStyleCoord(eStyleUnit_Auto);
mainAxisCoord = &autoStyleCoord;
} else {
// For all other flex-basis values, we just swap in the flex-basis
// itself for the main-size property here:
mainAxisCoord = flexBasis;
}
}
}
@ -5916,9 +5929,23 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(gfxContext* aRenderingConte
// inlineStyleCoord and blockStyleCoord in nsFrame::ComputeSize().
const nsStyleCoord* flexBasis = &(stylePos->mFlexBasis);
if (flexBasis->GetUnit() != eStyleUnit_Auto) {
// Override whichever styleCoord is in flex container's main axis:
(flexMainAxis == eLogicalAxisInline ?
inlineStyleCoord : blockStyleCoord) = flexBasis;
// Replace our main-axis styleCoord pointer with a different one,
// depending on our flex-basis value.
auto& mainAxisCoord = (flexMainAxis == eLogicalAxisInline
? inlineStyleCoord : blockStyleCoord);
if (flexBasis->GetUnit() == eStyleUnit_Enumerated &&
flexBasis->GetIntValue() == NS_STYLE_FLEX_BASIS_CONTENT) {
// We have 'flex-basis: content', which is equivalent to
// 'flex-basis:auto; {main-size}: auto'. So, just swap in a dummy
// 'auto' value to use for the main size property:
static const nsStyleCoord autoStyleCoord(eStyleUnit_Auto);
mainAxisCoord = &autoStyleCoord;
} else {
// For all other flex-basis values, we just swap in the flex-basis
// itself for the main-size property here:
mainAxisCoord = flexBasis;
}
}
}
}
@ -11007,14 +11034,19 @@ IsFrameScrolledOutOfView(nsIFrame* aTarget,
}
nsIFrame *scrollableParent = do_QueryFrame(scrollableFrame);
nsRect scrollableRect =
scrollableParent->GetVisualOverflowRectRelativeToSelf();
// We consider that the target is scrolled out if the scrollable frame is
// empty.
if (scrollableRect.IsEmpty()) {
return true;
}
nsRect transformedRect =
nsLayoutUtils::TransformFrameRectToAncestor(aTarget,
aTargetRect,
scrollableParent);
nsRect scrollableRect =
scrollableParent->GetVisualOverflowRectRelativeToSelf();
if (transformedRect.IsEmpty()) {
// If the transformed rect is empty it represents a line or a point that we
// should check is outside the the scrollable rect.

View File

@ -0,0 +1,77 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>CSS Reftest Reference</title>
<meta charset="utf-8">
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
<link rel="stylesheet" type="text/css" href="support/ahem.css">
<style>
.container {
display: flex;
flex-direction: row;
justify-content: space-between;
border: 2px solid purple;
padding: 2px;
margin-bottom: 2em;
height: 50px;
width: 200px;
}
.container > * {
flex-shrink: 0;
min-width: 0;
border: 2px solid teal;
}
.smallText { font: 10px Ahem; }
.bigText { font: 20px Ahem; }
.spacerChild::before {
content: '';
display: block;
background: brown;
height: 10px;
width: 10px;
}
.justPadding {
/* Empty div with 5px padding on each side */
padding: 5px;
background: cyan;
}
canvas { background: fuchsia }
</style>
</head>
<body>
<!-- Flex items have unspecified size properties: -->
<div class="container">
<div class="smallText">a b</div>
<div class="bigText">c</div>
<div class="spacerChild"></div>
<div class="justPadding"></div>
<canvas width="20"></canvas>
</div>
<!-- Various specified main-size values, in testcase
(removed here in reference case, because they shouldn't affect sizing): -->
<div class="container">
<div class="smallText">a b</div>
<div class="bigText">c</div>
<div class="spacerChild"></div>
<div class="justPadding"></div>
<canvas width="20"></canvas>
</div>
<!-- Various specified cross-size values (should be honored): -->
<div class="container">
<div class="smallText" style="height: 0px">a b</div>
<div class="bigText" style="height: 40px">c</div>
<div class="spacerChild" style="height: 20px"></div>
<div class="justPadding" style="height: 10px"></div>
<canvas width="20" style="height: 8px"></canvas>
</div>
</body>
</html>

View File

@ -0,0 +1,83 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>
CSS Test: Testing "flex-basis: content" in a row-oriented flex container
</title>
<meta charset="utf-8">
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
<link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#propdef-flex-basis">
<link rel="match" href="flexbox-flex-basis-content-001-ref.html">
<link rel="stylesheet" type="text/css" href="support/ahem.css">
<style>
.container {
display: flex;
flex-direction: row;
justify-content: space-between;
border: 2px solid purple;
padding: 2px;
margin-bottom: 2em;
height: 50px;
width: 200px;
}
.container > * {
/* All flex items have "flex-basis: content" (and zero flex-shrink and
min-main-size, to avoid any influence from those). */
flex-basis: content;
flex-shrink: 0;
min-width: 0;
border: 2px solid teal;
}
.smallText { font: 10px Ahem; }
.bigText { font: 20px Ahem; }
.spacerChild::before {
content: '';
display: block;
background: brown;
height: 10px;
width: 10px;
}
.justPadding {
/* Empty div with 5px padding on each side */
padding: 5px;
background: cyan;
}
canvas { background: fuchsia }
</style>
</head>
<body>
<!-- Flex items have unspecified size properties: -->
<div class="container">
<div class="smallText">a b</div>
<div class="bigText">c</div>
<div class="spacerChild"></div>
<div class="justPadding"></div>
<canvas width="20"></canvas>
</div>
<!-- Various specified main-size values (should be ignored): -->
<div class="container">
<div class="smallText" style="width: 0px">a b</div>
<div class="bigText" style="width: 40px">c</div>
<div class="spacerChild" style="width: 20px"></div>
<div class="justPadding" style="width: 10px"></div>
<canvas width="20" style="width: 8px"></canvas>
</div>
<!-- Various specified cross-size values (should be honored): -->
<div class="container">
<div class="smallText" style="height: 0px">a b</div>
<div class="bigText" style="height: 40px">c</div>
<div class="spacerChild" style="height: 20px"></div>
<div class="justPadding" style="height: 10px"></div>
<canvas width="20" style="height: 8px"></canvas>
</div>
</body>
</html>

View File

@ -0,0 +1,83 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>
CSS Test: Testing "flex-basis: content" (set via the "flex" shorthand)
in a row-oriented flex container.
</title>
<meta charset="utf-8">
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
<link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#propdef-flex-basis">
<link rel="match" href="flexbox-flex-basis-content-001-ref.html">
<link rel="stylesheet" type="text/css" href="support/ahem.css">
<style>
.container {
display: flex;
flex-direction: row;
justify-content: space-between;
border: 2px solid purple;
padding: 2px;
margin-bottom: 2em;
height: 50px;
width: 200px;
}
.container > * {
/* All flex items have "flex-basis: content" (and zero flex-shrink and
min-main-size, to avoid any influence from those). */
flex: 0 0 content;
min-width: 0;
border: 2px solid teal;
}
.smallText { font: 10px Ahem; }
.bigText { font: 20px Ahem; }
.spacerChild::before {
content: '';
display: block;
background: brown;
height: 10px;
width: 10px;
}
.justPadding {
/* Empty div with 5px padding on each side */
padding: 5px;
background: cyan;
}
canvas { background: fuchsia }
</style>
</head>
<body>
<!-- Flex items have unspecified size properties: -->
<div class="container">
<div class="smallText">a b</div>
<div class="bigText">c</div>
<div class="spacerChild"></div>
<div class="justPadding"></div>
<canvas width="20"></canvas>
</div>
<!-- Various specified main-size values (should be ignored): -->
<div class="container">
<div class="smallText" style="width: 0px">a b</div>
<div class="bigText" style="width: 40px">c</div>
<div class="spacerChild" style="width: 20px"></div>
<div class="justPadding" style="width: 10px"></div>
<canvas width="20" style="width: 8px"></canvas>
</div>
<!-- Various specified cross-size values (should be honored): -->
<div class="container">
<div class="smallText" style="height: 0px">a b</div>
<div class="bigText" style="height: 40px">c</div>
<div class="spacerChild" style="height: 20px"></div>
<div class="justPadding" style="height: 10px"></div>
<canvas width="20" style="height: 8px"></canvas>
</div>
</body>
</html>

View File

@ -0,0 +1,78 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>CSS Reftest Reference</title>
<meta charset="utf-8">
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
<link rel="stylesheet" type="text/css" href="support/ahem.css">
<style>
.container {
display: flex;
flex-direction: column;
justify-content: space-between;
border: 2px solid purple;
padding: 2px;
margin-right: 2em;
width: 50px;
height: 200px;
float: left;
}
.container > * {
flex-shrink: 0;
min-height: 0;
border: 2px solid teal;
}
.smallText { font: 10px Ahem; }
.bigText { font: 20px Ahem; }
.spacerChild::before {
content: '';
display: block;
background: brown;
height: 10px;
width: 10px;
}
.justPadding {
/* Empty div with 5px padding on each side */
padding: 5px;
background: cyan;
}
canvas { background: fuchsia }
</style>
</head>
<body>
<!-- Flex items have unspecified size properties: -->
<div class="container">
<div class="smallText">a b</div>
<div class="bigText">c</div>
<div class="spacerChild"></div>
<div class="justPadding"></div>
<canvas height="20"></canvas>
</div>
<!-- Various specified main-size values, in testcase
(removed here in reference case, because they shouldn't affect sizing): -->
<div class="container">
<div class="smallText">a b</div>
<div class="bigText">c</div>
<div class="spacerChild"></div>
<div class="justPadding"></div>
<canvas height="20"></canvas>
</div>
<!-- Various specified cross-size values (should be honored): -->
<div class="container">
<div class="smallText" style="width: 0px">a b</div>
<div class="bigText" style="width: 40px">c</div>
<div class="spacerChild" style="width: 20px"></div>
<div class="justPadding" style="width: 10px"></div>
<canvas height="20" style="width: 8px"></canvas>
</div>
</body>
</html>

View File

@ -0,0 +1,84 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>
CSS Test: Testing "flex-basis: content" in a column-oriented flex container
</title>
<meta charset="utf-8">
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
<link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#propdef-flex-basis">
<link rel="match" href="flexbox-flex-basis-content-002-ref.html">
<link rel="stylesheet" type="text/css" href="support/ahem.css">
<style>
.container {
display: flex;
flex-direction: column;
justify-content: space-between;
border: 2px solid purple;
padding: 2px;
margin-right: 2em;
width: 50px;
height: 200px;
float: left;
}
.container > * {
/* All flex items have "flex-basis: content" (and zero flex-shrink and
min-main-size, to avoid any influence from those). */
flex-basis: content;
flex-shrink: 0;
min-height: 0;
border: 2px solid teal;
}
.smallText { font: 10px Ahem; }
.bigText { font: 20px Ahem; }
.spacerChild::before {
content: '';
display: block;
background: brown;
height: 10px;
width: 10px;
}
.justPadding {
/* Empty div with 5px padding on each side */
padding: 5px;
background: cyan;
}
canvas { background: fuchsia }
</style>
</head>
<body>
<!-- Flex items have unspecified size properties: -->
<div class="container">
<div class="smallText">a b</div>
<div class="bigText">c</div>
<div class="spacerChild"></div>
<div class="justPadding"></div>
<canvas height="20"></canvas>
</div>
<!-- Various specified main-size values (should be ignored): -->
<div class="container">
<div class="smallText" style="height: 0px">a b</div>
<div class="bigText" style="height: 40px">c</div>
<div class="spacerChild" style="height: 20px"></div>
<div class="justPadding" style="height: 10px"></div>
<canvas height="20" style="height: 8px"></canvas>
</div>
<!-- Various specified cross-size values (should be honored): -->
<div class="container">
<div class="smallText" style="width: 0px">a b</div>
<div class="bigText" style="width: 40px">c</div>
<div class="spacerChild" style="width: 20px"></div>
<div class="justPadding" style="width: 10px"></div>
<canvas height="20" style="width: 8px"></canvas>
</div>
</body>
</html>

View File

@ -0,0 +1,84 @@
<!DOCTYPE html>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>
CSS Test: Testing "flex-basis: content" (set via the "flex" shorthand)
in a column-oriented flex container.
</title>
<meta charset="utf-8">
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
<link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#propdef-flex-basis">
<link rel="match" href="flexbox-flex-basis-content-002-ref.html">
<link rel="stylesheet" type="text/css" href="support/ahem.css">
<style>
.container {
display: flex;
flex-direction: column;
justify-content: space-between;
border: 2px solid purple;
padding: 2px;
margin-right: 2em;
width: 50px;
height: 200px;
float: left;
}
.container > * {
/* All flex items have "flex-basis: content" (and zero flex-shrink and
min-main-size, to avoid any influence from those). */
flex: 0 0 content;
min-height: 0;
border: 2px solid teal;
}
.smallText { font: 10px Ahem; }
.bigText { font: 20px Ahem; }
.spacerChild::before {
content: '';
display: block;
background: brown;
height: 10px;
width: 10px;
}
.justPadding {
/* Empty div with 5px padding on each side */
padding: 5px;
background: cyan;
}
canvas { background: fuchsia }
</style>
</head>
<body>
<!-- Flex items have unspecified size properties: -->
<div class="container">
<div class="smallText">a b</div>
<div class="bigText">c</div>
<div class="spacerChild"></div>
<div class="justPadding"></div>
<canvas height="20"></canvas>
</div>
<!-- Various specified main-size values (should be ignored): -->
<div class="container">
<div class="smallText" style="height: 0px">a b</div>
<div class="bigText" style="height: 40px">c</div>
<div class="spacerChild" style="height: 20px"></div>
<div class="justPadding" style="height: 10px"></div>
<canvas height="20" style="height: 8px"></canvas>
</div>
<!-- Various specified cross-size values (should be honored): -->
<div class="container">
<div class="smallText" style="width: 0px">a b</div>
<div class="bigText" style="width: 40px">c</div>
<div class="spacerChild" style="width: 20px"></div>
<div class="justPadding" style="width: 10px"></div>
<canvas height="20" style="width: 8px"></canvas>
</div>
</body>
</html>

View File

@ -97,6 +97,12 @@ fuzzy-if(Android,158,32) == flexbox-align-self-vert-rtl-001.xhtml flexbox-align
== flexbox-collapsed-item-horiz-002.html flexbox-collapsed-item-horiz-002-ref.html
== flexbox-collapsed-item-horiz-003.html flexbox-collapsed-item-horiz-003-ref.html
# Tests for "flex-basis: content"
== flexbox-flex-basis-content-001a.html flexbox-flex-basis-content-001-ref.html
== flexbox-flex-basis-content-001b.html flexbox-flex-basis-content-001-ref.html
== flexbox-flex-basis-content-002a.html flexbox-flex-basis-content-002-ref.html
== flexbox-flex-basis-content-002b.html flexbox-flex-basis-content-002-ref.html
# Tests for flex-flow shorthand property
== flexbox-flex-flow-001.html flexbox-flex-flow-001-ref.html
== flexbox-flex-flow-002.html flexbox-flex-flow-002-ref.html

View File

@ -206,6 +206,7 @@ CSS_KEY(column, column)
CSS_KEY(column-reverse, column_reverse)
CSS_KEY(condensed, condensed)
CSS_KEY(contain, contain)
CSS_KEY(content, content)
CSS_KEY(content-box, content_box)
CSS_KEY(contents, contents)
CSS_KEY(context-fill, context_fill)

View File

@ -1186,7 +1186,7 @@ CSS_PROP_COLUMN(
ColumnGap,
0,
"",
VARIANT_HL | VARIANT_NORMAL | VARIANT_CALC,
VARIANT_HLP | VARIANT_NORMAL | VARIANT_CALC,
nullptr,
eStyleAnimType_Coord)
CSS_PROP_SHORTHAND(
@ -1406,7 +1406,7 @@ CSS_PROP_POSITION(
// its own code to parse each subproperty. It does not depend on the
// longhand parsing defined here.
VARIANT_AHKLP | VARIANT_CALC,
kWidthKTable,
kFlexBasisKTable,
eStyleAnimType_Coord)
CSS_PROP_POSITION(
flex-direction,

View File

@ -1914,6 +1914,20 @@ const KTableEntry nsCSSProps::kWidthKTable[] = {
{ eCSSKeyword_UNKNOWN, -1 }
};
// This must be the same as kWidthKTable, but just with 'content' added:
const KTableEntry nsCSSProps::kFlexBasisKTable[] = {
{ eCSSKeyword__moz_max_content, NS_STYLE_WIDTH_MAX_CONTENT },
{ eCSSKeyword__moz_min_content, NS_STYLE_WIDTH_MIN_CONTENT },
{ eCSSKeyword__moz_fit_content, NS_STYLE_WIDTH_FIT_CONTENT },
{ eCSSKeyword__moz_available, NS_STYLE_WIDTH_AVAILABLE },
{ eCSSKeyword_content, NS_STYLE_FLEX_BASIS_CONTENT },
{ eCSSKeyword_UNKNOWN, -1 }
};
static_assert(ArrayLength(nsCSSProps::kFlexBasisKTable) ==
ArrayLength(nsCSSProps::kWidthKTable) + 1,
"kFlexBasisKTable should have the same entries as "
"kWidthKTable, plus one more for 'content'");
const KTableEntry nsCSSProps::kWindowDraggingKTable[] = {
{ eCSSKeyword_default, StyleWindowDragging::Default },
{ eCSSKeyword_drag, StyleWindowDragging::Drag },

View File

@ -680,6 +680,7 @@ public:
static const KTableEntry kVolumeKTable[];
static const KTableEntry kWhitespaceKTable[];
static const KTableEntry kWidthKTable[]; // also min-width, max-width
static const KTableEntry kFlexBasisKTable[];
static const KTableEntry kWindowDraggingKTable[];
static const KTableEntry kWindowShadowKTable[];
static const KTableEntry kWordBreakKTable[];

View File

@ -4777,7 +4777,7 @@ nsComputedDOMStyle::DoGetFlexBasis()
// }
SetValueToCoord(val, StylePosition()->mFlexBasis, true,
nullptr, nsCSSProps::kWidthKTable);
nullptr, nsCSSProps::kFlexBasisKTable);
return val.forget();
}

View File

@ -676,6 +676,12 @@ enum class StyleGridTrackBreadth : uint8_t {
#define NS_STYLE_WIDTH_MIN_CONTENT 1
#define NS_STYLE_WIDTH_FIT_CONTENT 2
#define NS_STYLE_WIDTH_AVAILABLE 3
// The 'content' keyword is only valid for 'flex-basis' (not for 'width'). But
// aside from that, the 'flex-basis' property accepts exactly the same values
// as 'width'. So I'm listing this one 'flex-basis'-specific enumerated value
// alongside the 'width' ones, to be sure we don't accidentally overload this
// numeric value with two different meanings if new 'width' keywords are added.
#define NS_STYLE_FLEX_BASIS_CONTENT 4
// See nsStyleDisplay.mPosition
#define NS_STYLE_POSITION_STATIC 0

View File

@ -2911,7 +2911,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleColumn
uint32_t mColumnCount; // [reset] see nsStyleConsts.h
nsStyleCoord mColumnWidth; // [reset] coord, auto
nsStyleCoord mColumnGap; // [reset] coord, normal
nsStyleCoord mColumnGap; // [reset] <length-percentage> | normal
mozilla::StyleComplexColor mColumnRuleColor; // [reset]
uint8_t mColumnRuleStyle; // [reset]

View File

@ -1710,7 +1710,7 @@ var gCSSProperties = {
inherited: false,
type: CSS_TYPE_LONGHAND,
initial_values: [ "normal" ],
other_values: [ "2px", "1em", "4em",
other_values: [ "2px", "1em", "4em", "3%", "calc(3%)", "calc(1em - 3%)",
"calc(2px)",
"calc(-2px)",
"calc(0px)",
@ -1721,7 +1721,7 @@ var gCSSProperties = {
"calc(25px*3)",
"calc(3*25px + 5em)",
],
invalid_values: [ "3%", "-1px", "4" ]
invalid_values: [ "-3%", "-1px", "4" ]
},
"-moz-column-gap": {
domProp: "MozColumnGap",
@ -4741,6 +4741,7 @@ var gCSSProperties = {
"calc(50px/(2 - 1))",
],
invalid_values: [ "none", "-2px",
"content", /* (valid for 'flex-basis' but not 'width') */
/* invalid calc() values */
"calc(50%+ 2px)",
"calc(50% +2px)",
@ -5256,12 +5257,14 @@ var gCSSProperties = {
inherited: false,
type: CSS_TYPE_LONGHAND,
initial_values: [ " auto" ],
// NOTE: This is cribbed directly from the "width" chunk, since this
// property takes the exact same values as width (albeit with
// different semantics on 'auto').
// NOTE: Besides "content", this is cribbed directly from the "width"
// chunk, since this property takes the exact same values as width
// (plus 'content' & with different semantics on 'auto').
// XXXdholbert (Maybe these should get separated out into
// a reusable array defined at the top of this file?)
other_values: [ "15px", "3em", "15%", "-moz-max-content", "-moz-min-content", "-moz-fit-content", "-moz-available",
other_values: [
"content",
"15px", "3em", "15%", "-moz-max-content", "-moz-min-content", "-moz-fit-content", "-moz-available",
// valid calc() values
"calc(-2px)",
"calc(2px)",

9
servo/Cargo.lock generated
View File

@ -1646,13 +1646,17 @@ dependencies = [
"cssparser 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)",
"hashglobe 0.1.0",
"hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper_serde 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"mozjs 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"selectors 0.19.0",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_bytes 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"servo_arc 0.1.1",
"smallbitvec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"string_cache 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"webrender_api 0.57.0 (git+https://github.com/servo/webrender)",
@ -1888,6 +1892,8 @@ dependencies = [
"ipc-channel 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"malloc_size_of 0.0.1",
"malloc_size_of_derive 0.0.1",
"matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"mime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"mime_guess 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1898,6 +1904,8 @@ dependencies = [
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-websocket 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
"servo_allocator 0.0.1",
"servo_arc 0.1.1",
"servo_config 0.0.1",
"servo_url 0.0.1",
"threadpool 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1937,6 +1945,7 @@ dependencies = [
"msg 0.0.1",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"servo_arc 0.1.1",
"servo_config 0.0.1",
"servo_url 0.0.1",
"url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -75,28 +75,16 @@ impl AxisSize {
fn from_flex_basis(
flex_basis: FlexBasis,
main_length: LengthOrPercentageOrAuto,
containing_length: Option<Au>
containing_length: Au,
) -> MaybeAuto {
match (flex_basis, containing_length) {
(GenericFlexBasis::Length(LengthOrPercentage::Length(length)), _) =>
MaybeAuto::Specified(Au::from(length)),
(GenericFlexBasis::Length(LengthOrPercentage::Percentage(percent)), Some(size)) =>
MaybeAuto::Specified(size.scale_by(percent.0)),
(GenericFlexBasis::Length(LengthOrPercentage::Percentage(_)), None) =>
MaybeAuto::Auto,
(GenericFlexBasis::Length(LengthOrPercentage::Calc(calc)), _) =>
MaybeAuto::from_option(calc.to_used_value(containing_length)),
(GenericFlexBasis::Content, _) =>
MaybeAuto::Auto,
(GenericFlexBasis::Auto, Some(size)) =>
MaybeAuto::from_style(main_length, size),
(GenericFlexBasis::Auto, None) => {
if let LengthOrPercentageOrAuto::Length(length) = main_length {
MaybeAuto::Specified(Au::from(length))
} else {
MaybeAuto::Auto
}
}
let width = match flex_basis {
GenericFlexBasis::Content => return MaybeAuto::Auto,
GenericFlexBasis::Width(width) => width,
};
match width.0 {
LengthOrPercentageOrAuto::Auto => MaybeAuto::from_style(main_length, containing_length),
other => MaybeAuto::from_style(other, containing_length),
}
}
@ -161,7 +149,7 @@ impl FlexItem {
Direction::Inline => {
let basis = from_flex_basis(block.fragment.style.get_position().flex_basis,
block.fragment.style.content_inline_size(),
Some(containing_length));
containing_length);
// These methods compute auto margins to zero length, which is exactly what we want.
block.fragment.compute_border_and_padding(containing_length);
@ -183,7 +171,7 @@ impl FlexItem {
Direction::Block => {
let basis = from_flex_basis(block.fragment.style.get_position().flex_basis,
block.fragment.style.content_block_size(),
Some(containing_length));
containing_length);
let content_size = block.fragment.border_box.size.block
- block.fragment.border_padding.block_start_end()
+ block.fragment.box_sizing_boundary(direction);

View File

@ -106,6 +106,7 @@ impl Flow for MulticolFlow {
{
let column_style = self.block_flow.fragment.style.get_column();
// FIXME(#20498): This should support percentages too.
let column_gap = match column_style.column_gap {
Either::First(len) => len.into(),
Either::Second(_normal) => self.block_flow.fragment.style.get_font().font_size.size(),

View File

@ -23,13 +23,17 @@ app_units = "0.6"
cssparser = "0.23.0"
euclid = "0.17"
hashglobe = { path = "../hashglobe" }
hyper = "0.10"
hyper_serde = "0.8"
mozjs = { version = "0.6", features = ["promises"], optional = true }
selectors = { path = "../selectors" }
serde = "1.0.27"
serde_bytes = { version = "0.10", optional = true }
servo_arc = { path = "../servo_arc" }
smallbitvec = "1.0.3"
smallvec = "0.6"
string_cache = { version = "0.7", optional = true }
time = "0.1.17"
url = { version = "1.2", optional = true }
webrender_api = { git = "https://github.com/servo/webrender", features = ["ipc"], optional = true }
xml5ever = { version = "0.12", optional = true }

View File

@ -47,9 +47,12 @@ extern crate app_units;
extern crate cssparser;
extern crate euclid;
extern crate hashglobe;
extern crate hyper;
extern crate hyper_serde;
#[cfg(feature = "servo")]
extern crate mozjs as js;
extern crate selectors;
extern crate serde;
#[cfg(feature = "servo")]
extern crate serde_bytes;
extern crate servo_arc;
@ -57,6 +60,7 @@ extern crate smallbitvec;
extern crate smallvec;
#[cfg(feature = "servo")]
extern crate string_cache;
extern crate time;
#[cfg(feature = "url")]
extern crate url;
extern crate void;
@ -69,6 +73,7 @@ extern crate xml5ever;
use serde_bytes::ByteBuf;
use std::hash::{BuildHasher, Hash};
use std::mem::size_of;
use std::ops::{Deref, DerefMut};
use std::ops::Range;
use std::os::raw::c_void;
use void::Void;
@ -591,6 +596,18 @@ impl<T: MallocSizeOf> MallocConditionalSizeOf for servo_arc::Arc<T> {
}
}
/// If a mutex is stored directly as a member of a data type that is being measured,
/// it is the unique owner of its contents and deserves to be measured.
///
/// If a mutex is stored inside of an Arc value as a member of a data type that is being measured,
/// the Arc will not be automatically measured so there is no risk of overcounting the mutex's
/// contents.
impl<T: MallocSizeOf> MallocSizeOf for std::sync::Mutex<T> {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
(*self.lock().unwrap()).size_of(ops)
}
}
impl MallocSizeOf for smallbitvec::SmallBitVec {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
if let Some(ptr) = self.heap_ptr() {
@ -802,3 +819,90 @@ impl MallocSizeOf for xml5ever::QualName {
self.local.size_of(ops)
}
}
impl MallocSizeOf for hyper::header::Headers {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
self.iter().fold(0, |acc, x| {
let name = x.name();
let raw = self.get_raw(name);
acc + raw.size_of(ops)
})
}
}
impl MallocSizeOf for hyper::header::ContentType {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
self.0.size_of(ops)
}
}
impl MallocSizeOf for hyper::mime::Mime {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
self.0.size_of(ops) +
self.1.size_of(ops) +
self.2.size_of(ops)
}
}
impl MallocSizeOf for hyper::mime::Attr {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
match *self {
hyper::mime::Attr::Ext(ref s) => s.size_of(ops),
_ => 0,
}
}
}
impl MallocSizeOf for hyper::mime::Value {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
self.len() // Length of string value in bytes (not the char length of a string)!
}
}
malloc_size_of_is_0!(time::Duration);
malloc_size_of_is_0!(time::Tm);
impl<T> MallocSizeOf for hyper_serde::Serde<T> where
for <'de> hyper_serde::De<T>: serde::Deserialize<'de>,
for <'a> hyper_serde::Ser<'a, T>: serde::Serialize,
T: MallocSizeOf {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
self.0.size_of(ops)
}
}
// Placeholder for unique case where internals of Sender cannot be measured.
// malloc size of is 0 macro complains about type supplied!
impl<T> MallocSizeOf for std::sync::mpsc::Sender<T> {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
0
}
}
impl MallocSizeOf for hyper::status::StatusCode {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
match *self {
hyper::status::StatusCode::Unregistered(u) => u.size_of(ops),
_ => 0,
}
}
}
/// Measurable that defers to inner value and used to verify MallocSizeOf implementation in a
/// struct.
#[derive(Clone)]
pub struct Measurable<T: MallocSizeOf> (pub T);
impl<T: MallocSizeOf> Deref for Measurable<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T: MallocSizeOf> DerefMut for Measurable<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}

View File

@ -24,6 +24,8 @@ immeta = "0.3.6"
ipc-channel = "0.10"
lazy_static = "1"
log = "0.4"
malloc_size_of = { path = "../malloc_size_of" }
malloc_size_of_derive = { path = "../malloc_size_of_derive" }
matches = "0.1"
mime = "0.2.1"
mime_guess = "1.8.0"
@ -33,6 +35,8 @@ openssl = "0.9"
profile_traits = {path = "../profile_traits"}
serde = "1.0"
serde_json = "1.0"
servo_allocator = {path = "../allocator"}
servo_arc = {path = "../servo_arc"}
servo_config = {path = "../config"}
servo_url = {path = "../url"}
servo-websocket = { version = "0.21", default-features = false, features = ["sync"] }

View File

@ -14,14 +14,17 @@ use hyper::header::Headers;
use hyper::method::Method;
use hyper::status::StatusCode;
use hyper_serde::Serde;
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps, MallocUnconditionalSizeOf, MallocUnconditionalShallowSizeOf};
use malloc_size_of::Measurable;
use net_traits::{Metadata, FetchMetadata};
use net_traits::request::Request;
use net_traits::response::{HttpsState, Response, ResponseBody};
use servo_arc::Arc;
use servo_config::prefs::PREFS;
use servo_url::ServoUrl;
use std::collections::HashMap;
use std::str;
use std::sync::{Arc, Mutex};
use std::sync::Mutex;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{channel, Sender};
use time;
@ -29,7 +32,7 @@ use time::{Duration, Tm};
/// The key used to differentiate requests in the cache.
#[derive(Clone, Eq, Hash, PartialEq)]
#[derive(Clone, Eq, Hash, MallocSizeOf, PartialEq )]
pub struct CacheKey {
url: ServoUrl
}
@ -56,9 +59,16 @@ impl CacheKey {
/// A complete cached resource.
#[derive(Clone)]
struct CachedResource {
metadata: CachedMetadata,
request_headers: Arc<Mutex<Headers>>,
body: Arc<Mutex<ResponseBody>>,
aborted: Arc<AtomicBool>,
awaiting_body: Arc<Mutex<Vec<Sender<Data>>>>,
data: Measurable<MeasurableCachedResource>
}
#[derive(Clone, MallocSizeOf)]
struct MeasurableCachedResource {
metadata: CachedMetadata,
location_url: Option<Result<ServoUrl, String>>,
https_state: HttpsState,
status: Option<StatusCode>,
@ -66,25 +76,47 @@ struct CachedResource {
url_list: Vec<ServoUrl>,
expires: Duration,
last_validated: Tm,
aborted: Arc<AtomicBool>,
awaiting_body: Arc<Mutex<Vec<Sender<Data>>>>
}
impl MallocSizeOf for CachedResource {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
self.request_headers.unconditional_size_of(ops) +
self.body.unconditional_size_of(ops) +
self.aborted.unconditional_size_of(ops) +
self.awaiting_body.unconditional_size_of(ops) +
self.data.size_of(ops)
}
}
/// Metadata about a loaded resource, such as is obtained from HTTP headers.
#[derive(Clone)]
struct CachedMetadata {
/// Headers
pub headers: Arc<Mutex<Headers>>,
/// Fields that implement MallocSizeOf
pub data: Measurable<MeasurableCachedMetadata>
}
#[derive(Clone, MallocSizeOf)]
struct MeasurableCachedMetadata {
/// Final URL after redirects.
pub final_url: ServoUrl,
/// MIME type / subtype.
pub content_type: Option<Serde<ContentType>>,
/// Character set.
pub charset: Option<String>,
/// Headers
pub headers: Arc<Mutex<Headers>>,
/// HTTP Status
pub status: Option<(u16, Vec<u8>)>
}
impl MallocSizeOf for CachedMetadata {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
self.headers.unconditional_shallow_size_of(ops) +
self.headers.size_of(ops) +
self.data.size_of(ops)
}
}
/// Wrapper around a cached response, including information on re-validation needs
pub struct CachedResponse {
/// The response constructed from the cached resource
@ -94,6 +126,7 @@ pub struct CachedResponse {
}
/// A memory cache.
#[derive(MallocSizeOf)]
pub struct HttpCache {
/// cached responses.
entries: HashMap<CacheKey, Vec<CachedResource>>,
@ -278,7 +311,7 @@ fn create_cached_response(request: &Request,
cached_headers: &Headers,
done_chan: &mut DoneChannel)
-> CachedResponse {
let mut response = Response::new(cached_resource.metadata.final_url.clone());
let mut response = Response::new(cached_resource.data.metadata.data.final_url.clone());
response.headers = cached_headers.clone();
response.body = cached_resource.body.clone();
if let ResponseBody::Receiving(_) = *cached_resource.body.lock().unwrap() {
@ -286,18 +319,18 @@ fn create_cached_response(request: &Request,
*done_chan = Some((done_sender.clone(), done_receiver));
cached_resource.awaiting_body.lock().unwrap().push(done_sender);
}
response.location_url = cached_resource.location_url.clone();
response.status = cached_resource.status.clone();
response.raw_status = cached_resource.raw_status.clone();
response.url_list = cached_resource.url_list.clone();
response.https_state = cached_resource.https_state.clone();
response.location_url = cached_resource.data.location_url.clone();
response.status = cached_resource.data.status.clone();
response.raw_status = cached_resource.data.raw_status.clone();
response.url_list = cached_resource.data.url_list.clone();
response.https_state = cached_resource.data.https_state.clone();
response.referrer = request.referrer.to_url().cloned();
response.referrer_policy = request.referrer_policy.clone();
response.aborted = cached_resource.aborted.clone();
let expires = cached_resource.expires;
let expires = cached_resource.data.expires;
let adjusted_expires = get_expiry_adjustment_from_request_headers(request, expires);
let now = Duration::seconds(time::now().to_timespec().sec);
let last_validated = Duration::seconds(cached_resource.last_validated.to_timespec().sec);
let last_validated = Duration::seconds(cached_resource.data.last_validated.to_timespec().sec);
let time_since_validated = now - last_validated;
// TODO: take must-revalidate into account <https://tools.ietf.org/html/rfc7234#section-5.2.2.1>
// TODO: if this cache is to be considered shared, take proxy-revalidate into account
@ -312,18 +345,20 @@ fn create_cached_response(request: &Request,
fn create_resource_with_bytes_from_resource(bytes: &[u8], resource: &CachedResource)
-> CachedResource {
CachedResource {
metadata: resource.metadata.clone(),
request_headers: resource.request_headers.clone(),
body: Arc::new(Mutex::new(ResponseBody::Done(bytes.to_owned()))),
location_url: resource.location_url.clone(),
https_state: resource.https_state.clone(),
status: Some(StatusCode::PartialContent),
raw_status: Some((206, b"Partial Content".to_vec())),
url_list: resource.url_list.clone(),
expires: resource.expires.clone(),
last_validated: resource.last_validated.clone(),
aborted: Arc::new(AtomicBool::new(false)),
awaiting_body: Arc::new(Mutex::new(vec![]))
awaiting_body: Arc::new(Mutex::new(vec![])),
data: Measurable(MeasurableCachedResource {
metadata: resource.data.metadata.clone(),
location_url: resource.data.location_url.clone(),
https_state: resource.data.https_state.clone(),
status: Some(StatusCode::PartialContent),
raw_status: Some((206, b"Partial Content".to_vec())),
url_list: resource.data.url_list.clone(),
expires: resource.data.expires.clone(),
last_validated: resource.data.last_validated.clone(),
})
}
}
@ -334,13 +369,13 @@ fn handle_range_request(request: &Request,
done_chan: &mut DoneChannel)
-> Option<CachedResponse> {
let mut complete_cached_resources = candidates.iter().filter(|resource| {
match resource.raw_status {
match resource.data.raw_status {
Some((ref code, _)) => *code == 200,
None => false
}
});
let partial_cached_resources = candidates.iter().filter(|resource| {
match resource.raw_status {
match resource.data.raw_status {
Some((ref code, _)) => *code == 206,
None => false
}
@ -361,7 +396,7 @@ fn handle_range_request(request: &Request,
let requested = body.get(b..e);
if let Some(bytes) = requested {
let new_resource = create_resource_with_bytes_from_resource(bytes, complete_resource);
let cached_headers = new_resource.metadata.headers.lock().unwrap();
let cached_headers = new_resource.data.metadata.headers.lock().unwrap();
let cached_response = create_cached_response(request, &new_resource, &*cached_headers, done_chan);
return Some(cached_response);
}
@ -369,7 +404,7 @@ fn handle_range_request(request: &Request,
},
(&header::ByteRangeSpec::FromTo(beginning, end), None) => {
for partial_resource in partial_cached_resources {
let headers = partial_resource.metadata.headers.lock().unwrap();
let headers = partial_resource.data.metadata.headers.lock().unwrap();
let content_range = headers.get::<header::ContentRange>();
let (res_beginning, res_end) = match content_range {
Some(&header::ContentRange(
@ -401,7 +436,7 @@ fn handle_range_request(request: &Request,
let requested = body.get(b..);
if let Some(bytes) = requested {
let new_resource = create_resource_with_bytes_from_resource(bytes, complete_resource);
let cached_headers = new_resource.metadata.headers.lock().unwrap();
let cached_headers = new_resource.data.metadata.headers.lock().unwrap();
let cached_response = create_cached_response(request, &new_resource, &*cached_headers, done_chan);
return Some(cached_response);
}
@ -409,7 +444,7 @@ fn handle_range_request(request: &Request,
},
(&header::ByteRangeSpec::AllFrom(beginning), None) => {
for partial_resource in partial_cached_resources {
let headers = partial_resource.metadata.headers.lock().unwrap();
let headers = partial_resource.data.metadata.headers.lock().unwrap();
let content_range = headers.get::<header::ContentRange>();
let (res_beginning, res_end, total) = match content_range {
Some(&header::ContentRange(
@ -441,7 +476,7 @@ fn handle_range_request(request: &Request,
let requested = body.get(from_byte..);
if let Some(bytes) = requested {
let new_resource = create_resource_with_bytes_from_resource(bytes, complete_resource);
let cached_headers = new_resource.metadata.headers.lock().unwrap();
let cached_headers = new_resource.data.metadata.headers.lock().unwrap();
let cached_response = create_cached_response(request, &new_resource, &*cached_headers, done_chan);
return Some(cached_response);
}
@ -449,7 +484,7 @@ fn handle_range_request(request: &Request,
},
(&header::ByteRangeSpec::Last(offset), None) => {
for partial_resource in partial_cached_resources {
let headers = partial_resource.metadata.headers.lock().unwrap();
let headers = partial_resource.data.metadata.headers.lock().unwrap();
let content_range = headers.get::<header::ContentRange>();
let (res_beginning, res_end, total) = match content_range {
Some(&header::ContentRange(
@ -501,7 +536,7 @@ impl HttpCache {
let mut candidates = vec![];
for cached_resource in resources {
let mut can_be_constructed = true;
let cached_headers = cached_resource.metadata.headers.lock().unwrap();
let cached_headers = cached_resource.data.metadata.headers.lock().unwrap();
let original_request_headers = cached_resource.request_headers.lock().unwrap();
if let Some(vary_data) = cached_headers.get_raw("Vary") {
// Calculating Secondary Keys with Vary <https://tools.ietf.org/html/rfc7234#section-4.1>
@ -554,7 +589,7 @@ impl HttpCache {
// Returning the first response that can be constructed
// TODO: select the most appropriate one, using a known mechanism from a selecting header field,
// or using the Date header to return the most recent one.
let cached_headers = cached_resource.metadata.headers.lock().unwrap();
let cached_headers = cached_resource.data.metadata.headers.lock().unwrap();
let cached_response = create_cached_response(request, cached_resource, &*cached_headers, done_chan);
return Some(cached_response);
}
@ -589,24 +624,24 @@ impl HttpCache {
let entry_key = CacheKey::new(request.clone());
if let Some(cached_resources) = self.entries.get_mut(&entry_key) {
for cached_resource in cached_resources.iter_mut() {
let mut stored_headers = cached_resource.metadata.headers.lock().unwrap();
// Received a response with 304 status code, in response to a request that matches a cached resource.
// 1. update the headers of the cached resource.
// 2. return a response, constructed from the cached resource.
stored_headers.extend(response.headers.iter());
let mut constructed_response = Response::new(cached_resource.metadata.final_url.clone());
constructed_response.headers = stored_headers.clone();
let mut constructed_response = Response::new(cached_resource.data.metadata.data.final_url.clone());
constructed_response.body = cached_resource.body.clone();
constructed_response.status = cached_resource.status.clone();
constructed_response.https_state = cached_resource.https_state.clone();
constructed_response.status = cached_resource.data.status.clone();
constructed_response.https_state = cached_resource.data.https_state.clone();
constructed_response.referrer = request.referrer.to_url().cloned();
constructed_response.referrer_policy = request.referrer_policy.clone();
constructed_response.raw_status = cached_resource.raw_status.clone();
constructed_response.url_list = cached_resource.url_list.clone();
constructed_response.raw_status = cached_resource.data.raw_status.clone();
constructed_response.url_list = cached_resource.data.url_list.clone();
// done_chan will have been set to Some by http_network_fetch,
// set it back to None since the response returned here replaces the 304 one from the network.
*done_chan = None;
cached_resource.expires = get_response_expiry(&constructed_response);
cached_resource.data.expires = get_response_expiry(&constructed_response);
let mut stored_headers = cached_resource.data.metadata.headers.lock().unwrap();
stored_headers.extend(response.headers.iter());
constructed_response.headers = stored_headers.clone();
return Some(constructed_response);
}
}
@ -617,7 +652,7 @@ impl HttpCache {
let entry_key = CacheKey::from_servo_url(url);
if let Some(cached_resources) = self.entries.get_mut(&entry_key) {
for cached_resource in cached_resources.iter_mut() {
cached_resource.expires = Duration::seconds(0i64);
cached_resource.data.expires = Duration::seconds(0i64);
}
}
}
@ -664,25 +699,29 @@ impl HttpCache {
}
let expiry = get_response_expiry(&response);
let cacheable_metadata = CachedMetadata {
final_url: metadata.final_url,
content_type: metadata.content_type,
charset: metadata.charset,
status: metadata.status,
headers: Arc::new(Mutex::new(response.headers.clone()))
headers: Arc::new(Mutex::new(response.headers.clone())),
data: Measurable(MeasurableCachedMetadata {
final_url: metadata.final_url,
content_type: metadata.content_type,
charset: metadata.charset,
status: metadata.status
})
};
let entry_resource = CachedResource {
metadata: cacheable_metadata,
request_headers: Arc::new(Mutex::new(request.headers.clone())),
body: response.body.clone(),
location_url: response.location_url.clone(),
https_state: response.https_state.clone(),
status: response.status.clone(),
raw_status: response.raw_status.clone(),
url_list: response.url_list.clone(),
expires: expiry,
last_validated: time::now(),
aborted: response.aborted.clone(),
awaiting_body: Arc::new(Mutex::new(vec![]))
awaiting_body: Arc::new(Mutex::new(vec![])),
data: Measurable(MeasurableCachedResource {
metadata: cacheable_metadata,
location_url: response.location_url.clone(),
https_state: response.https_state.clone(),
status: response.status.clone(),
raw_status: response.raw_status.clone(),
url_list: response.url_list.clone(),
expires: expiry,
last_validated: time::now()
})
};
let entry = self.entries.entry(entry_key).or_insert(vec![]);
entry.push(entry_resource);

View File

@ -17,6 +17,8 @@ extern crate ipc_channel;
#[macro_use]
extern crate lazy_static;
#[macro_use] extern crate log;
extern crate malloc_size_of;
#[macro_use] extern crate malloc_size_of_derive;
#[macro_use] #[no_link] extern crate matches;
#[macro_use]
extern crate mime;
@ -24,9 +26,12 @@ extern crate mime_guess;
extern crate msg;
extern crate net_traits;
extern crate openssl;
#[macro_use]
extern crate profile_traits;
#[macro_use] extern crate serde;
extern crate serde_json;
extern crate servo_allocator;
extern crate servo_arc;
extern crate servo_config;
extern crate servo_url;
extern crate time;

View File

@ -16,6 +16,7 @@ use http_cache::HttpCache;
use http_loader::{HttpState, http_redirect_fetch};
use hyper_serde::Serde;
use ipc_channel::ipc::{self, IpcReceiver, IpcReceiverSet, IpcSender};
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use net_traits::{CookieSource, CoreResourceThread};
use net_traits::{CoreResourceMsg, CustomResponseMediator, FetchChannels};
use net_traits::{FetchResponseMsg, ResourceThreads, WebSocketDomAction};
@ -23,9 +24,12 @@ use net_traits::WebSocketNetworkEvent;
use net_traits::request::{Request, RequestInit};
use net_traits::response::{Response, ResponseInit};
use net_traits::storage_thread::StorageThreadMsg;
use profile_traits::mem::{Report, ReportsChan, ReportKind};
use profile_traits::mem::ProfilerChan as MemProfilerChan;
use profile_traits::time::ProfilerChan;
use serde::{Deserialize, Serialize};
use serde_json;
use servo_allocator;
use servo_config::opts;
use servo_config::resource_files::resources_dir_path;
use servo_url::ServoUrl;
@ -47,13 +51,15 @@ const TFD_PROVIDER: &'static TFDProvider = &TFDProvider;
/// Returns a tuple of (public, private) senders to the new threads.
pub fn new_resource_threads(user_agent: Cow<'static, str>,
devtools_chan: Option<Sender<DevtoolsControlMsg>>,
profiler_chan: ProfilerChan,
time_profiler_chan: ProfilerChan,
mem_profiler_chan: MemProfilerChan,
config_dir: Option<PathBuf>)
-> (ResourceThreads, ResourceThreads) {
let (public_core, private_core) = new_core_resource_thread(
user_agent,
devtools_chan,
profiler_chan,
time_profiler_chan,
mem_profiler_chan,
config_dir.clone());
let storage: IpcSender<StorageThreadMsg> = StorageThreadFactory::new(config_dir);
(ResourceThreads::new(public_core, storage.clone()),
@ -64,22 +70,34 @@ pub fn new_resource_threads(user_agent: Cow<'static, str>,
/// Create a CoreResourceThread
pub fn new_core_resource_thread(user_agent: Cow<'static, str>,
devtools_chan: Option<Sender<DevtoolsControlMsg>>,
profiler_chan: ProfilerChan,
time_profiler_chan: ProfilerChan,
mem_profiler_chan: MemProfilerChan,
config_dir: Option<PathBuf>)
-> (CoreResourceThread, CoreResourceThread) {
let (public_setup_chan, public_setup_port) = ipc::channel().unwrap();
let (private_setup_chan, private_setup_port) = ipc::channel().unwrap();
let (report_chan, report_port) = ipc::channel().unwrap();
thread::Builder::new().name("ResourceManager".to_owned()).spawn(move || {
let resource_manager = CoreResourceManager::new(
user_agent, devtools_chan, profiler_chan
user_agent, devtools_chan, time_profiler_chan
);
let mut channel_manager = ResourceChannelManager {
resource_manager: resource_manager,
config_dir: config_dir,
};
channel_manager.start(public_setup_port,
private_setup_port);
mem_profiler_chan.run_with_memory_reporting(|| (
channel_manager.start(
public_setup_port,
private_setup_port,
report_port)
),
String::from("network-cache-reporter"),
report_chan,
|report_chan| report_chan);
}).expect("Thread spawning failed");
(public_setup_chan, private_setup_chan)
}
@ -127,31 +145,69 @@ impl ResourceChannelManager {
#[allow(unsafe_code)]
fn start(&mut self,
public_receiver: IpcReceiver<CoreResourceMsg>,
private_receiver: IpcReceiver<CoreResourceMsg>) {
private_receiver: IpcReceiver<CoreResourceMsg>,
memory_reporter: IpcReceiver<ReportsChan>) {
let (public_http_state, private_http_state) =
create_http_states(self.config_dir.as_ref().map(Deref::deref));
let mut rx_set = IpcReceiverSet::new().unwrap();
let private_id = rx_set.add(private_receiver).unwrap();
let public_id = rx_set.add(public_receiver).unwrap();
let reporter_id = rx_set.add(memory_reporter).unwrap();
loop {
for (id, data) in rx_set.select().unwrap().into_iter().map(|m| m.unwrap()) {
let group = if id == private_id {
&private_http_state
for receiver in rx_set.select().unwrap().into_iter() {
// Handles case where profiler thread shuts down before resource thread.
match receiver {
ipc::IpcSelectionResult::ChannelClosed(..) => continue,
_ => {}
}
let (id, data) = receiver.unwrap();
// If message is memory report, get the size_of of public and private http caches
if id == reporter_id {
if let Ok(msg) = data.to() {
self.process_report(msg, &private_http_state, &public_http_state);
continue;
}
} else {
assert_eq!(id, public_id);
&public_http_state
};
if let Ok(msg) = data.to() {
if !self.process_msg(msg, group) {
return;
let group = if id == private_id {
&private_http_state
} else {
assert_eq!(id, public_id);
&public_http_state
};
if let Ok(msg) = data.to() {
if !self.process_msg(msg, group) {
return;
}
}
}
}
}
}
fn process_report(&mut self,
msg: ReportsChan,
public_http_state: &Arc<HttpState>,
private_http_state: &Arc<HttpState>) {
let mut ops = MallocSizeOfOps::new(servo_allocator::usable_size, None, None);
let public_cache = public_http_state.http_cache.read().unwrap();
let private_cache = private_http_state.http_cache.read().unwrap();
let public_report = Report {
path: path!["memory-cache", "public"],
kind: ReportKind::ExplicitJemallocHeapSize,
size: public_cache.size_of(&mut ops)
};
let private_report = Report {
path: path!["memory-cache", "private"],
kind: ReportKind::ExplicitJemallocHeapSize,
size: private_cache.size_of(&mut ops)
};
msg.send(vec!(public_report, private_report));
}
/// Returns false if the thread should exit.
fn process_msg(&mut self,

View File

@ -6,6 +6,7 @@ use ipc_channel::ipc;
use net::resource_thread::new_core_resource_thread;
use net::test::parse_hostsfile;
use net_traits::CoreResourceMsg;
use profile_traits::mem::ProfilerChan as MemProfilerChan;
use profile_traits::time::ProfilerChan;
use std::net::IpAddr;
@ -16,9 +17,10 @@ fn ip(s: &str) -> IpAddr {
#[test]
fn test_exit() {
let (tx, _rx) = ipc::channel().unwrap();
let (mtx, _mrx) = ipc::channel().unwrap();
let (sender, receiver) = ipc::channel().unwrap();
let (resource_thread, _private_resource_thread) = new_core_resource_thread(
"".into(), None, ProfilerChan(tx), None);
"".into(), None, ProfilerChan(tx), MemProfilerChan(mtx), None);
resource_thread.send(CoreResourceMsg::Exit(sender)).unwrap();
receiver.recv().unwrap();
}

View File

@ -24,6 +24,7 @@ malloc_size_of_derive = { path = "../malloc_size_of_derive" }
msg = {path = "../msg"}
num-traits = "0.1.32"
serde = "1.0"
servo_arc = {path = "../servo_arc"}
servo_config = {path = "../config"}
servo_url = {path = "../url"}
url = "1.2"

View File

@ -17,6 +17,7 @@ extern crate ipc_channel;
extern crate msg;
extern crate num_traits;
#[macro_use] extern crate serde;
extern crate servo_arc;
extern crate servo_config;
extern crate servo_url;
extern crate url;

View File

@ -8,8 +8,9 @@ use {FetchMetadata, FilteredMetadata, Metadata, NetworkError, ReferrerPolicy};
use hyper::header::{AccessControlExposeHeaders, ContentType, Headers};
use hyper::status::StatusCode;
use hyper_serde::Serde;
use servo_arc::Arc;
use servo_url::ServoUrl;
use std::sync::{Arc, Mutex};
use std::sync::Mutex;
use std::sync::atomic::AtomicBool;
/// [Response type](https://fetch.spec.whatwg.org/#concept-response-type)

View File

@ -8,6 +8,7 @@
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER;
use serde;
use std::marker::Send;
use std::sync::mpsc::Sender;
@ -25,6 +26,14 @@ impl<T> OpaqueSender<T> for Sender<T> {
}
}
impl<T> OpaqueSender<T> for IpcSender<T> where T: serde::Serialize {
fn send(&self, message: T) {
if let Err(e) = IpcSender::send(self, message) {
warn!("Error communicating with the target thread from the profiler: {}", e);
}
}
}
/// Front-end representation of the profiler used to communicate with the
/// profiler.
#[derive(Clone, Deserialize, Serialize)]

View File

@ -462,6 +462,7 @@ fn create_constellation(user_agent: Cow<'static, str>,
new_resource_threads(user_agent,
devtools_chan.clone(),
time_profiler_chan.clone(),
mem_profiler_chan.clone(),
config_dir);
let font_cache_thread = FontCacheThread::new(public_resource_threads.sender(),
webrender_api_sender.create_api());

View File

@ -489,6 +489,7 @@ pub mod root {
pub const NS_STYLE_WIDTH_MIN_CONTENT: u32 = 1;
pub const NS_STYLE_WIDTH_FIT_CONTENT: u32 = 2;
pub const NS_STYLE_WIDTH_AVAILABLE: u32 = 3;
pub const NS_STYLE_FLEX_BASIS_CONTENT: u32 = 4;
pub const NS_STYLE_POSITION_STATIC: u32 = 0;
pub const NS_STYLE_POSITION_RELATIVE: u32 = 1;
pub const NS_STYLE_POSITION_ABSOLUTE: u32 = 2;

View File

@ -10,7 +10,7 @@ use Atom;
use app_units::Au;
use counter_style::{Symbol, Symbols};
use cssparser::RGBA;
use gecko_bindings::structs::{CounterStylePtr, nsStyleCoord};
use gecko_bindings::structs::{self, CounterStylePtr, nsStyleCoord};
use gecko_bindings::structs::{StyleGridTrackBreadth, StyleShapeRadius};
use gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
use media_queries::Device;
@ -21,10 +21,12 @@ use values::computed::{Angle, ExtremumLength, Length, LengthOrPercentage, Length
use values::computed::{LengthOrPercentageOrNone, Number, NumberOrPercentage};
use values::computed::{MaxLength, MozLength, Percentage};
use values::computed::{NonNegativeLength, NonNegativeLengthOrPercentage, NonNegativeNumber};
use values::computed::FlexBasis as ComputedFlexBasis;
use values::computed::basic_shape::ShapeRadius as ComputedShapeRadius;
use values::generics::{CounterStyleOrNone, NonNegative};
use values::generics::basic_shape::ShapeRadius;
use values::generics::box_::Perspective;
use values::generics::flex::FlexBasis;
use values::generics::gecko::ScrollSnapPoint;
use values::generics::grid::{TrackBreadth, TrackKeyword};
@ -59,6 +61,31 @@ impl<A: GeckoStyleCoordConvertible, B: GeckoStyleCoordConvertible> GeckoStyleCoo
}
}
impl GeckoStyleCoordConvertible for ComputedFlexBasis {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
match *self {
FlexBasis::Content => {
coord.set_value(
CoordDataValue::Enumerated(structs::NS_STYLE_FLEX_BASIS_CONTENT)
)
},
FlexBasis::Width(ref w) => w.to_gecko_style_coord(coord),
}
}
fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
if let Some(width) = MozLength::from_gecko_style_coord(coord) {
return Some(FlexBasis::Width(width))
}
if let CoordDataValue::Enumerated(structs::NS_STYLE_FLEX_BASIS_CONTENT) = coord.as_value() {
return Some(FlexBasis::Content)
}
None
}
}
impl GeckoStyleCoordConvertible for Number {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
coord.set_value(CoordDataValue::Factor(*self));

View File

@ -1445,7 +1445,8 @@ impl Clone for ${style_struct.gecko_struct_name} {
"length::LengthOrAuto": impl_style_coord,
"length::LengthOrNormal": impl_style_coord,
"length::NonNegativeLengthOrAuto": impl_style_coord,
"length::NonNegativeLengthOrNormal": impl_style_coord,
"length::NonNegativeLengthOrPercentageOrNormal": impl_style_coord,
"FlexBasis": impl_style_coord,
"Length": impl_absolute_length,
"LengthOrNormal": impl_style_coord,
"LengthOrPercentage": impl_style_coord,
@ -1748,14 +1749,14 @@ fn static_assert() {
<% skip_position_longhands = " ".join(x.ident for x in SIDES + GRID_LINES) %>
<%self:impl_trait style_struct_name="Position"
skip_longhands="${skip_position_longhands} z-index order align-content
justify-content align-self justify-self align-items
justify-items grid-auto-rows grid-auto-columns grid-auto-flow
grid-template-areas grid-template-rows grid-template-columns">
skip_longhands="${skip_position_longhands} z-index order
align-content justify-content align-self
justify-self align-items justify-items
grid-auto-rows grid-auto-columns
grid-auto-flow grid-template-areas
grid-template-rows grid-template-columns">
% for side in SIDES:
<% impl_split_style_coord("%s" % side.ident,
"mOffset",
side.index) %>
<% impl_split_style_coord(side.ident, "mOffset", side.index) %>
% endfor
pub fn set_z_index(&mut self, v: longhands::z_index::computed_value::T) {

View File

@ -29,14 +29,21 @@ ${helpers.predefined_type(
servo_restyle_damage="rebuild_and_reflow",
)}
${helpers.predefined_type("column-gap",
"length::NonNegativeLengthOrNormal",
"Either::Second(Normal)",
extra_prefixes="moz",
servo_pref="layout.columns.enabled",
animation_value_type="NonNegativeLengthOrNormal",
spec="https://drafts.csswg.org/css-multicol/#propdef-column-gap",
servo_restyle_damage = "reflow")}
<%
# FIXME(#20498): Servo should support percentages in column-gap.
col_gap_type = "NonNegativeLengthOrPercentageOrNormal" if product == "gecko" else "NonNegativeLengthOrNormal"
%>
${helpers.predefined_type(
"column-gap",
"length::%s" % col_gap_type,
"Either::Second(Normal)",
extra_prefixes="moz",
servo_pref="layout.columns.enabled",
animation_value_type=col_gap_type,
spec="https://drafts.csswg.org/css-multicol/#propdef-column-gap",
servo_restyle_damage = "reflow",
)}
${helpers.single_keyword("column-fill", "balance auto", extra_prefixes="moz",
products="gecko", animation_value_type="discrete",

View File

@ -206,93 +206,15 @@ ${helpers.predefined_type(
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-style",
)}
<%helpers:longhand name="text-emphasis-position" animation_value_type="discrete" products="gecko"
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-position">
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq)]
#[derive(ToComputedValue, ToCss)]
pub enum HorizontalWritingModeValue {
Over,
Under,
}
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq)]
#[derive(ToComputedValue, ToCss)]
pub enum VerticalWritingModeValue {
Right,
Left,
}
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)]
pub struct SpecifiedValue(pub HorizontalWritingModeValue, pub VerticalWritingModeValue);
pub mod computed_value {
pub type T = super::SpecifiedValue;
}
pub fn get_initial_value() -> computed_value::T {
SpecifiedValue(HorizontalWritingModeValue::Over, VerticalWritingModeValue::Right)
}
pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
if let Ok(horizontal) = input.try(|input| HorizontalWritingModeValue::parse(input)) {
let vertical = VerticalWritingModeValue::parse(input)?;
Ok(SpecifiedValue(horizontal, vertical))
} else {
let vertical = VerticalWritingModeValue::parse(input)?;
let horizontal = HorizontalWritingModeValue::parse(input)?;
Ok(SpecifiedValue(horizontal, vertical))
}
}
% if product == "gecko":
impl SpecifiedValue {
pub fn from_gecko_keyword(kw: u32) -> Self {
use gecko_bindings::structs;
let vert = if kw & structs::NS_STYLE_TEXT_EMPHASIS_POSITION_RIGHT != 0 {
VerticalWritingModeValue::Right
} else {
debug_assert!(kw & structs::NS_STYLE_TEXT_EMPHASIS_POSITION_LEFT != 0);
VerticalWritingModeValue::Left
};
let horiz = if kw & structs::NS_STYLE_TEXT_EMPHASIS_POSITION_OVER != 0 {
HorizontalWritingModeValue::Over
} else {
debug_assert!(kw & structs::NS_STYLE_TEXT_EMPHASIS_POSITION_UNDER != 0);
HorizontalWritingModeValue::Under
};
SpecifiedValue(horiz, vert)
}
}
impl From<u8> for SpecifiedValue {
fn from(bits: u8) -> SpecifiedValue {
SpecifiedValue::from_gecko_keyword(bits as u32)
}
}
impl From<SpecifiedValue> for u8 {
fn from(v: SpecifiedValue) -> u8 {
use gecko_bindings::structs;
let mut result = match v.0 {
HorizontalWritingModeValue::Over => structs::NS_STYLE_TEXT_EMPHASIS_POSITION_OVER,
HorizontalWritingModeValue::Under => structs::NS_STYLE_TEXT_EMPHASIS_POSITION_UNDER,
};
match v.1 {
VerticalWritingModeValue::Right => {
result |= structs::NS_STYLE_TEXT_EMPHASIS_POSITION_RIGHT;
}
VerticalWritingModeValue::Left => {
result |= structs::NS_STYLE_TEXT_EMPHASIS_POSITION_LEFT;
}
};
result as u8
}
}
% endif
</%helpers:longhand>
${helpers.predefined_type(
"text-emphasis-position",
"TextEmphasisPosition",
"computed::TextEmphasisPosition::over_right()",
initial_specified_value="specified::TextEmphasisPosition::over_right()",
products="gecko",
animation_value_type="discrete",
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-position",
)}
${helpers.predefined_type(
"text-emphasis-color",

View File

@ -174,32 +174,16 @@ ${helpers.predefined_type("order", "Integer", "0",
spec="https://drafts.csswg.org/css-flexbox/#order-property",
servo_restyle_damage = "reflow")}
% if product == "gecko":
// FIXME: Gecko doesn't support content value yet.
//
// FIXME(emilio): I suspect this property shouldn't allow quirks, and this
// was just a mistake, it's kind of justificable to support it given the
// spec grammar is just `content | <width>`, but other browsers don't...
${helpers.predefined_type(
"flex-basis",
"MozLength",
"computed::MozLength::auto()",
extra_prefixes="webkit",
animation_value_type="MozLength",
allow_quirks=True,
spec="https://drafts.csswg.org/css-flexbox/#flex-basis-property",
servo_restyle_damage = "reflow"
)}
% else:
// FIXME: This property should be animatable.
${helpers.predefined_type("flex-basis",
"FlexBasis",
"computed::FlexBasis::auto()",
spec="https://drafts.csswg.org/css-flexbox/#flex-basis-property",
extra_prefixes="webkit",
animation_value_type="none",
servo_restyle_damage = "reflow")}
% endif
${helpers.predefined_type(
"flex-basis",
"FlexBasis",
"computed::FlexBasis::auto()",
spec="https://drafts.csswg.org/css-flexbox/#flex-basis-property",
extra_prefixes="webkit",
animation_value_type="FlexBasis",
servo_restyle_damage = "reflow"
)}
% for (size, logical) in ALL_SIZES:
<%
spec = "https://drafts.csswg.org/css-box/#propdef-%s"

View File

@ -4,8 +4,23 @@
//! Computed types for CSS values related to flexbox.
use values::computed::length::LengthOrPercentage;
use values::generics::flex::FlexBasis as GenericFlexBasis;
/// The `width` value type.
#[cfg(feature = "servo")]
pub type Width = ::values::computed::NonNegativeLengthOrPercentageOrAuto;
/// The `width` value type.
#[cfg(feature = "gecko")]
pub type Width = ::values::computed::MozLength;
/// A computed value for the `flex-basis` property.
pub type FlexBasis = GenericFlexBasis<LengthOrPercentage>;
pub type FlexBasis = GenericFlexBasis<Width>;
impl FlexBasis {
/// `auto`
#[inline]
pub fn auto() -> Self {
GenericFlexBasis::Width(Width::auto())
}
}

View File

@ -427,10 +427,10 @@ impl LengthOrPercentage {
pub fn clamp_to_non_negative(self) -> Self {
match self {
LengthOrPercentage::Length(length) => {
LengthOrPercentage::Length(Length::new(length.px().max(0.)))
LengthOrPercentage::Length(length.clamp_to_non_negative())
},
LengthOrPercentage::Percentage(percentage) => {
LengthOrPercentage::Percentage(Percentage(percentage.0.max(0.)))
LengthOrPercentage::Percentage(percentage.clamp_to_non_negative())
},
_ => self
}
@ -511,6 +511,31 @@ impl LengthOrPercentageOrAuto {
}
}
/// A wrapper of LengthOrPercentageOrAuto, whose value must be >= 0.
pub type NonNegativeLengthOrPercentageOrAuto = NonNegative<LengthOrPercentageOrAuto>;
impl NonNegativeLengthOrPercentageOrAuto {
/// `auto`
#[inline]
pub fn auto() -> Self {
NonNegative(LengthOrPercentageOrAuto::Auto)
}
}
impl ToAnimatedValue for NonNegativeLengthOrPercentageOrAuto {
type AnimatedValue = LengthOrPercentageOrAuto;
#[inline]
fn to_animated_value(self) -> Self::AnimatedValue {
self.0
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
NonNegative(animated.clamp_to_non_negative())
}
}
impl LengthOrPercentageOrAuto {
/// Returns true if the computed value is absolute 0 or 0%.
///
@ -524,6 +549,15 @@ impl LengthOrPercentageOrAuto {
Calc(_) | Auto => false
}
}
fn clamp_to_non_negative(self) -> Self {
use self::LengthOrPercentageOrAuto::*;
match self {
Length(l) => Length(l.clamp_to_non_negative()),
Percentage(p) => Percentage(p.clamp_to_non_negative()),
_ => self,
}
}
}
impl ToComputedValue for specified::LengthOrPercentageOrAuto {
@ -737,6 +771,11 @@ impl CSSPixelLength {
self.0
}
#[inline]
fn clamp_to_non_negative(self) -> Self {
Self::new(self.px().max(0.))
}
/// Return the length with app_unit i32 type.
#[inline]
pub fn to_i32_au(&self) -> i32 {
@ -897,6 +936,9 @@ pub type NonNegativeLengthOrAuto = Either<NonNegativeLength, Auto>;
/// Either a computed NonNegativeLength or the `normal` keyword.
pub type NonNegativeLengthOrNormal = Either<NonNegativeLength, Normal>;
/// Either a computed NonNegativeLengthOrPercentage or the `normal` keyword.
pub type NonNegativeLengthOrPercentageOrNormal = Either<NonNegativeLengthOrPercentage, Normal>;
/// A type for possible values for min- and max- flavors of width, height,
/// block-size, and inline-size.
#[allow(missing_docs)]

View File

@ -60,7 +60,8 @@ pub use super::{Auto, Either, None_};
pub use super::specified::{BorderStyle, TextDecorationLine};
pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNumber, LengthOrPercentage};
pub use self::length::{LengthOrPercentageOrAuto, LengthOrPercentageOrNone, MaxLength, MozLength};
pub use self::length::{CSSPixelLength, ExtremumLength, NonNegativeLength, NonNegativeLengthOrPercentage};
pub use self::length::{CSSPixelLength, ExtremumLength, NonNegativeLength};
pub use self::length::{NonNegativeLengthOrPercentage, NonNegativeLengthOrPercentageOrAuto};
pub use self::list::{ListStyleImage, Quotes};
#[cfg(feature = "gecko")]
pub use self::list::ListStyleType;
@ -75,7 +76,7 @@ pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
pub use self::svg::MozContextProperties;
pub use self::table::XSpan;
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, MozTabSize};
pub use self::text::{TextAlign, TextEmphasisStyle, TextOverflow, WordSpacing};
pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle, TextOverflow, WordSpacing};
pub use self::time::Time;
pub use self::transform::{Rotate, Scale, TimingFunction, Transform, TransformOperation};
pub use self::transform::{TransformOrigin, TransformStyle, Translate};

View File

@ -32,6 +32,12 @@ impl Percentage {
pub fn abs(&self) -> Self {
Percentage(self.0.abs())
}
/// Clamps this percentage to a non-negative percentage.
#[inline]
pub fn clamp_to_non_negative(self) -> Self {
Percentage(self.0.max(0.))
}
}
impl ToCss for Percentage {

View File

@ -18,6 +18,7 @@ use values::generics::text::Spacing;
use values::specified::text::{TextDecorationLine, TextEmphasisFillMode, TextEmphasisShapeKeyword, TextOverflowSide};
pub use values::specified::TextAlignKeyword as TextAlign;
pub use values::specified::TextEmphasisPosition;
/// A computed value for the `initial-letter` property.
pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>;

View File

@ -4,34 +4,13 @@
//! Generic types for CSS values related to flexbox.
use values::computed::Percentage;
/// A generic value for the `flex-basis` property.
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
#[derive(Clone, Copy, Debug, PartialEq, ToComputedValue, ToCss)]
pub enum FlexBasis<LengthOrPercentage> {
/// `auto`
Auto,
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq)]
#[derive(ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)]
pub enum FlexBasis<Width> {
/// `content`
Content,
/// `<length-percentage>`
Length(LengthOrPercentage),
}
impl<L> FlexBasis<L> {
/// Returns `auto`.
#[inline]
pub fn auto() -> Self {
FlexBasis::Auto
}
}
impl<L> FlexBasis<L>
where Percentage: Into<L>,
{
/// Returns `0%`.
#[inline]
pub fn zero_percent() -> Self {
FlexBasis::Length(Percentage(0.).into())
}
/// `<width>`
Width(Width),
}

View File

@ -8,22 +8,42 @@ use cssparser::Parser;
use parser::{Parse, ParserContext};
use style_traits::ParseError;
use values::generics::flex::FlexBasis as GenericFlexBasis;
use values::specified::length::LengthOrPercentage;
/// The `width` value type.
#[cfg(feature = "servo")]
pub type Width = ::values::specified::NonNegativeLengthOrPercentageOrAuto;
/// The `width` value type.
#[cfg(feature = "gecko")]
pub type Width = ::values::specified::MozLength;
/// A specified value for the `flex-basis` property.
pub type FlexBasis = GenericFlexBasis<LengthOrPercentage>;
pub type FlexBasis = GenericFlexBasis<Width>;
impl Parse for FlexBasis {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>)
-> Result<Self, ParseError<'i>> {
if let Ok(length) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
return Ok(GenericFlexBasis::Length(length));
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if let Ok(width) = input.try(|i| Width::parse(context, i)) {
return Ok(GenericFlexBasis::Width(width));
}
try_match_ident_ignore_ascii_case! { input,
"auto" => Ok(GenericFlexBasis::Auto),
"content" => Ok(GenericFlexBasis::Content),
}
}
}
impl FlexBasis {
/// `auto`
#[inline]
pub fn auto() -> Self {
GenericFlexBasis::Width(Width::auto())
}
/// `0%`
#[inline]
pub fn zero_percent() -> Self {
GenericFlexBasis::Width(Width::zero_percent())
}
}

View File

@ -679,9 +679,6 @@ impl NonNegativeLength {
}
}
/// Either a NonNegativeLength or the `normal` keyword.
pub type NonNegativeLengthOrNormal = Either<NonNegativeLength, Normal>;
/// Either a NonNegativeLength or the `auto` keyword.
pub type NonNegativeLengthOrAuto = Either<NonNegativeLength, Auto>;
@ -917,6 +914,16 @@ impl LengthOrPercentageOrAuto {
pub fn zero_percent() -> Self {
LengthOrPercentageOrAuto::Percentage(computed::Percentage::zero())
}
/// Parses, with quirks.
#[inline]
pub fn parse_quirky<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks,
) -> Result<Self, ParseError<'i>> {
Self::parse_internal(context, input, AllowedNumericType::All, allow_quirks)
}
}
impl Parse for LengthOrPercentageOrAuto {
@ -926,14 +933,33 @@ impl Parse for LengthOrPercentageOrAuto {
}
}
impl LengthOrPercentageOrAuto {
/// Parses, with quirks.
/// A wrapper of LengthOrPercentageOrAuto, whose value must be >= 0.
pub type NonNegativeLengthOrPercentageOrAuto = NonNegative<LengthOrPercentageOrAuto>;
impl NonNegativeLengthOrPercentageOrAuto {
/// 0
#[inline]
pub fn parse_quirky<'i, 't>(context: &ParserContext,
input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks)
-> Result<Self, ParseError<'i>> {
Self::parse_internal(context, input, AllowedNumericType::All, allow_quirks)
pub fn zero() -> Self {
NonNegative(LengthOrPercentageOrAuto::zero())
}
/// 0%
#[inline]
pub fn zero_percent() -> Self {
NonNegative(LengthOrPercentageOrAuto::zero_percent())
}
/// `auto`
#[inline]
pub fn auto() -> Self {
NonNegative(LengthOrPercentageOrAuto::Auto)
}
}
impl Parse for NonNegativeLengthOrPercentageOrAuto {
#[inline]
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Ok(NonNegative(LengthOrPercentageOrAuto::parse_non_negative(context, input)?))
}
}
@ -1020,6 +1046,12 @@ impl Parse for LengthOrPercentageOrNone {
/// A wrapper of LengthOrPercentage, whose value must be >= 0.
pub type NonNegativeLengthOrPercentage = NonNegative<LengthOrPercentage>;
/// Either a computed NonNegativeLength or the `normal` keyword.
pub type NonNegativeLengthOrNormal = Either<NonNegativeLength, Normal>;
/// Either a NonNegativeLengthOrPercentage or the `normal` keyword.
pub type NonNegativeLengthOrPercentageOrNormal = Either<NonNegativeLengthOrPercentage, Normal>;
impl From<NoCalcLength> for NonNegativeLengthOrPercentage {
#[inline]
fn from(len: NoCalcLength) -> Self {
@ -1087,8 +1119,11 @@ impl LengthOrNumber {
}
/// A value suitable for a `min-width` or `min-height` property.
/// Unlike `max-width` or `max-height` properties, a MozLength can be
/// `auto`, and cannot be `none`.
///
/// Unlike `max-width` or `max-height` properties, a MozLength can be `auto`,
/// and cannot be `none`.
///
/// Note that it only accepts non-negative values.
#[allow(missing_docs)]
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
pub enum MozLength {

View File

@ -55,7 +55,7 @@ pub use self::length::{FontRelativeLength, Length, LengthOrNumber};
pub use self::length::{LengthOrPercentage, LengthOrPercentageOrAuto};
pub use self::length::{LengthOrPercentageOrNone, MaxLength, MozLength};
pub use self::length::{NoCalcLength, ViewportPercentageLength};
pub use self::length::NonNegativeLengthOrPercentage;
pub use self::length::{NonNegativeLengthOrPercentage, NonNegativeLengthOrPercentageOrAuto};
pub use self::list::{ListStyleImage, Quotes};
#[cfg(feature = "gecko")]
pub use self::list::ListStyleType;
@ -71,7 +71,8 @@ pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
pub use self::svg::MozContextProperties;
pub use self::table::XSpan;
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, MozTabSize, TextAlign, TextEmphasisStyle};
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, MozTabSize, TextAlign};
pub use self::text::{TextEmphasisStyle, TextEmphasisPosition};
pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpacing};
pub use self::time::Time;
pub use self::transform::{Rotate, Scale, TimingFunction, Transform};

View File

@ -666,6 +666,106 @@ impl Parse for TextEmphasisStyle {
}
}
/// The allowed horizontal values for the `text-emphasis-position` property.
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq)]
#[derive(ToComputedValue, ToCss)]
pub enum TextEmphasisHorizontalWritingModeValue {
/// Draw marks over the text in horizontal writing mode.
Over,
/// Draw marks under the text in horizontal writing mode.
Under,
}
/// The allowed vertical values for the `text-emphasis-position` property.
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq)]
#[derive(ToComputedValue, ToCss)]
pub enum TextEmphasisVerticalWritingModeValue {
/// Draws marks to the right of the text in vertical writing mode.
Right,
/// Draw marks to the left of the text in vertical writing mode.
Left,
}
/// Specified value of `text-emphasis-position` property.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)]
pub struct TextEmphasisPosition(
pub TextEmphasisHorizontalWritingModeValue,
pub TextEmphasisVerticalWritingModeValue
);
impl TextEmphasisPosition {
#[inline]
/// Returns the initial value of `text-emphasis-position`
pub fn over_right() -> Self {
TextEmphasisPosition(TextEmphasisHorizontalWritingModeValue::Over,
TextEmphasisVerticalWritingModeValue::Right)
}
#[cfg(feature = "gecko")]
/// Converts an enumerated value coming from Gecko to a `TextEmphasisPosition`.
pub fn from_gecko_keyword(kw: u32) -> Self {
use gecko_bindings::structs;
let vert = if kw & structs::NS_STYLE_TEXT_EMPHASIS_POSITION_RIGHT != 0 {
TextEmphasisVerticalWritingModeValue::Right
} else {
debug_assert!(kw & structs::NS_STYLE_TEXT_EMPHASIS_POSITION_LEFT != 0);
TextEmphasisVerticalWritingModeValue::Left
};
let horiz = if kw & structs::NS_STYLE_TEXT_EMPHASIS_POSITION_OVER != 0 {
TextEmphasisHorizontalWritingModeValue::Over
} else {
debug_assert!(kw & structs::NS_STYLE_TEXT_EMPHASIS_POSITION_UNDER != 0);
TextEmphasisHorizontalWritingModeValue::Under
};
TextEmphasisPosition(horiz, vert)
}
}
impl Parse for TextEmphasisPosition {
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>
) -> Result<Self, ParseError<'i>> {
if let Ok(horizontal) = input.try(|input| TextEmphasisHorizontalWritingModeValue::parse(input)) {
let vertical = TextEmphasisVerticalWritingModeValue::parse(input)?;
Ok(TextEmphasisPosition(horizontal, vertical))
} else {
let vertical = TextEmphasisVerticalWritingModeValue::parse(input)?;
let horizontal = TextEmphasisHorizontalWritingModeValue::parse(input)?;
Ok(TextEmphasisPosition(horizontal, vertical))
}
}
}
#[cfg(feature = "gecko")]
impl From<u8> for TextEmphasisPosition {
fn from(bits: u8) -> Self {
TextEmphasisPosition::from_gecko_keyword(bits as u32)
}
}
#[cfg(feature = "gecko")]
impl From<TextEmphasisPosition> for u8 {
fn from(v: TextEmphasisPosition) -> u8 {
use gecko_bindings::structs;
let mut result = match v.0 {
TextEmphasisHorizontalWritingModeValue::Over => structs::NS_STYLE_TEXT_EMPHASIS_POSITION_OVER,
TextEmphasisHorizontalWritingModeValue::Under => structs::NS_STYLE_TEXT_EMPHASIS_POSITION_UNDER,
};
match v.1 {
TextEmphasisVerticalWritingModeValue::Right => {
result |= structs::NS_STYLE_TEXT_EMPHASIS_POSITION_RIGHT;
}
TextEmphasisVerticalWritingModeValue::Left => {
result |= structs::NS_STYLE_TEXT_EMPHASIS_POSITION_LEFT;
}
};
result as u8
}
}
/// A specified value for the `-moz-tab-size` property.
pub type MozTabSize = GenericMozTabSize<NonNegativeNumber, NonNegativeLength>;

View File

@ -8,7 +8,6 @@ use style::properties::{PropertyDeclaration, Importance};
use style::properties::declaration_block::PropertyDeclarationBlock;
use style::properties::parse_property_declaration_list;
use style::values::{CustomIdent, RGBA};
use style::values::generics::flex::FlexBasis;
use style::values::specified::{BorderStyle, BorderSideWidth, Color};
use style::values::specified::{Length, LengthOrPercentage, LengthOrPercentageOrAuto};
use style::values::specified::NoCalcLength;
@ -559,42 +558,6 @@ mod shorthand_serialization {
}
}
#[test]
fn flex_should_serialize_all_available_properties() {
use style::values::specified::{NonNegativeNumber, Percentage};
let mut properties = Vec::new();
let grow = NonNegativeNumber::new(2f32);
let shrink = NonNegativeNumber::new(3f32);
let basis =
FlexBasis::Length(Percentage::new(0.5f32).into());
properties.push(PropertyDeclaration::FlexGrow(grow));
properties.push(PropertyDeclaration::FlexShrink(shrink));
properties.push(PropertyDeclaration::FlexBasis(basis));
let serialization = shorthand_properties_to_string(properties);
assert_eq!(serialization, "flex: 2 3 50%;");
}
#[test]
fn flex_flow_should_serialize_all_available_properties() {
use style::properties::longhands::flex_direction::SpecifiedValue as FlexDirection;
use style::properties::longhands::flex_wrap::SpecifiedValue as FlexWrap;
let mut properties = Vec::new();
let direction = FlexDirection::Row;
let wrap = FlexWrap::Wrap;
properties.push(PropertyDeclaration::FlexDirection(direction));
properties.push(PropertyDeclaration::FlexWrap(wrap));
let serialization = shorthand_properties_to_string(properties);
assert_eq!(serialization, "flex-flow: row wrap;");
}
mod background {
use super::*;

View File

@ -1,4 +0,0 @@
[column-gap-parsing-001.html]
[column-gap accepts percentage]
expected: FAIL

View File

@ -1,4 +0,0 @@
[grid-column-gap-parsing-001.html]
[column-gap accepts percentage]
expected: FAIL

View File

@ -1,37 +1,7 @@
[multicol-gap-percentage-001.html]
[.multicol 1]
expected: FAIL
[.multicol 2]
expected: FAIL
[.multicol 3]
expected: FAIL
[.multicol 4]
expected: FAIL
[.multicol 5]
expected: FAIL
[.multicol 6]
expected: FAIL
[.multicol 7]
expected: FAIL
[.multicol 8]
expected: FAIL
[.multicol 9]
expected: FAIL
[.multicol 10]
expected: FAIL
[.multicol 11]
expected: FAIL
[.multicol 12]
expected: FAIL

View File

@ -0,0 +1 @@
{"files":{".travis.yml":"bdb52df624876cdf4a9214bb2a81cefcf7ed7176b7213045846a68ead3a5c56f","Cargo.toml":"5d897604ce6935387b66cb58cbd15af0fbf70a6f9aa18dc5a524d92946cb4fcb","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"d5b3226768e22b6dd11270c92e1e4bab9acdfa7e5b2fc1efaddcf3fbf00aff05","README.md":"e4d2cfe8f354ea78d25b51d817ed172c8569b434badaec74b4e8551f30be01e9","bors.toml":"1d8a7a56c5c76925a3daa8c50a40cc82cbfc638f521f864106bd60b1e8a219a2","rustfmt.toml":"cad0c47fc0d3c55c5c2144efc4935f830bf720190267c416b9ee484ebbc3604d","src/lib.rs":"1d58d926c22e1027f0037609176361b19a9693d582f9e5349440eebd72d62d79","tests/supported.rs":"29912bd33d6b6ea0b8985f23b75af4ef4419017ce5cd4b3bc1fc8349af2e0952","tests/tokens.rs":"d7effb9466553820a65bee2ed250c93d60cffe7065fdf6d389e967ef80297efc"},"package":"0997ad463f64ce6ba02cf5af320622bb9782e4f8355b650a2cc7ccca69a7cc2e"}

View File

@ -0,0 +1,8 @@
language: rust
rust:
- nightly
- beta
- stable
branches:
except:
- staging.tmp

50
third_party/rust/hyper_serde/Cargo.toml vendored Normal file
View File

@ -0,0 +1,50 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g. crates.io) dependencies
#
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
[package]
name = "hyper_serde"
version = "0.8.0"
authors = ["Anthony Ramine <n.oxyde@gmail.com>"]
description = "Serde support for Hyper types"
documentation = "https://docs.rs/hyper_serde"
keywords = ["serde", "serialization", "hyper", "cookie", "mime"]
categories = ["encoding", "web-programming"]
license = "MIT/Apache-2.0"
repository = "https://github.com/nox/hyper_serde"
[lib]
doctest = false
[dependencies.time]
version = "0.1"
[dependencies.cookie]
version = "0.10"
default-features = false
[dependencies.mime]
version = "0.2"
[dependencies.serde]
version = "1.0"
[dependencies.hyper]
version = "0.10"
[dependencies.serde_bytes]
version = "0.10"
[dev-dependencies.serde_test]
version = "1.0"
[dev-dependencies.time]
version = "0.1"
[badges.travis-ci]
repository = "nox/hyper_serde"

View File

@ -0,0 +1,176 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View File

@ -0,0 +1,19 @@
Copyright (c) 2016 Anthony Ramine
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

40
third_party/rust/hyper_serde/README.md vendored Normal file
View File

@ -0,0 +1,40 @@
Serde support for Hyper types
=============================
This crate provides wrappers and convenience functions to support [Serde] for
some types defined in [cookie], [Hyper], [mime] and [time].
[cookie]: https://github.com/alexcrichton/cookie-rs
[Hyper]: https://github.com/hyperium/hyper
[mime]: https://github.com/hyperium/mime.rs
[Serde]: https://github.com/serde-rs/serde
[time]: https://github.com/rust-lang-deprecated/time
The supported types are:
* `cookie::Cookie`
* `hyper::header::ContentType`
* `hyper::header::Headers`
* `hyper::http::RawStatus`
* `hyper::method::Method`
* `mime::Mime`
* `time::Tm`
For more details, see the crate documentation.
## License
hyper_serde is licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
http://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in hyper_serde by you, as defined in the Apache-2.0 license,
shall be dual licensed as above, without any additional terms or conditions.

View File

@ -0,0 +1 @@
status = ["continuous-integration/travis-ci/push"]

View File

@ -0,0 +1,8 @@
match_block_trailing_comma = true
max_width = 80
newline_style = "Unix"
normalize_comments = true
reorder_imported_names = true
reorder_imports = true
use_try_shorthand = true
where_trailing_comma = true

536
third_party/rust/hyper_serde/src/lib.rs vendored Normal file
View File

@ -0,0 +1,536 @@
//! This crate provides wrappers and convenience functions to make Hyper and
//! Serde work hand in hand.
//!
//! The supported types are:
//!
//! * `cookie::Cookie`
//! * `hyper::header::ContentType`
//! * `hyper::header::Headers`
//! * `hyper::http::RawStatus`
//! * `hyper::method::Method`
//! * `mime::Mime`
//! * `time::Tm`
//!
//! # How do I use a data type with a `Headers` member with Serde?
//!
//! Use the serde attributes `deserialize_with` and `serialize_with`.
//!
//! ```
//! struct MyStruct {
//! #[serde(deserialize_with = "hyper_serde::deserialize",
//! serialize_with = "hyper_serde::serialize")]
//! headers: Headers,
//! }
//! ```
//!
//! # How do I encode a `Headers` value with `serde_json::to_string`?
//!
//! Use the `Ser` wrapper.
//!
//! ```
//! serde_json::to_string(&Ser::new(&headers))
//! ```
//!
//! # How do I decode a `Method` value with `serde_json::parse`?
//!
//! Use the `De` wrapper.
//!
//! ```
//! serde_json::parse::<De<Method>>("\"PUT\"").map(De::into_inner)
//! ```
//!
//! # How do I send `Cookie` values as part of an IPC channel?
//!
//! Use the `Serde` wrapper. It implements `Deref` and `DerefMut` for
//! convenience.
//!
//! ```
//! ipc::channel::<Serde<Cookie>>()
//! ```
//!
//!
#![deny(missing_docs)]
#![deny(unsafe_code)]
extern crate cookie;
extern crate hyper;
extern crate mime;
extern crate serde;
extern crate serde_bytes;
extern crate time;
use cookie::Cookie;
use hyper::header::{ContentType, Headers};
use hyper::http::RawStatus;
use hyper::method::Method;
use mime::Mime;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_bytes::{ByteBuf, Bytes};
use serde::de::{self, MapAccess, SeqAccess, Visitor};
use serde::ser::{SerializeMap, SerializeSeq};
use std::cmp;
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::str;
use time::{Tm, strptime};
/// Deserialises a `T` value with a given deserializer.
///
/// This is useful to deserialize Hyper types used in structure fields or
/// tuple members with `#[serde(deserialize_with = "hyper_serde::deserialize")]`.
#[inline(always)]
pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
where D: Deserializer<'de>,
De<T>: Deserialize<'de>,
{
De::deserialize(deserializer).map(De::into_inner)
}
/// Serialises `value` with a given serializer.
///
/// This is useful to serialize Hyper types used in structure fields or
/// tuple members with `#[serde(serialize_with = "hyper_serde::serialize")]`.
#[inline(always)]
pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer,
for<'a> Ser<'a, T>: Serialize,
{
Ser::new(value).serialize(serializer)
}
/// Serialises `value` with a given serializer in a pretty way.
///
/// This does the same job as `serialize` but with a prettier format
/// for some combinations of types and serialisers.
///
/// For now, the only change from `serialize` is when serialising `Headers`,
/// where the items in the header values get serialised as strings instead
/// of sequences of bytes, if they represent UTF-8 text.
#[inline(always)]
pub fn serialize_pretty<T, S>(value: &T,
serializer: S)
-> Result<S::Ok, S::Error>
where S: Serializer,
for<'a> Ser<'a, T>: Serialize,
{
Ser::new_pretty(value).serialize(serializer)
}
/// A wrapper to deserialize Hyper types.
///
/// This is useful with functions such as `serde_json::from_str`.
///
/// Values of this type can only be obtained through
/// the `serde::Deserialize` trait.
#[derive(Debug)]
pub struct De<T> {
v: T,
}
impl<T> De<T> {
fn new(v: T) -> Self {
De { v: v }
}
}
impl<'de, T> De<T>
where De<T>: Deserialize<'de>,
{
/// Consumes this wrapper, returning the deserialized value.
#[inline(always)]
pub fn into_inner(self) -> T {
self.v
}
}
/// A wrapper to serialize Hyper types.
///
/// This is useful with functions such as `serde_json::to_string`.
///
/// Values of this type can only be passed to the `serde::Serialize` trait.
#[derive(Debug)]
pub struct Ser<'a, T: 'a> {
v: &'a T,
pretty: bool,
}
impl<'a, T> Ser<'a, T>
where Ser<'a, T>: serde::Serialize,
{
/// Returns a new `Ser` wrapper.
#[inline(always)]
pub fn new(value: &'a T) -> Self {
Ser {
v: value,
pretty: false,
}
}
/// Returns a new `Ser` wrapper, in pretty mode.
///
/// See `serialize_pretty`.
#[inline(always)]
pub fn new_pretty(value: &'a T) -> Self {
Ser {
v: value,
pretty: true,
}
}
}
/// A convenience wrapper to be used as a type parameter, for example when
/// a `Vec<T>` need to be passed to serde.
#[derive(Clone, PartialEq)]
pub struct Serde<T>(pub T)
where for<'de> De<T>: Deserialize<'de>,
for<'a> Ser<'a, T>: Serialize;
impl<T> Serde<T>
where for<'de> De<T>: Deserialize<'de>,
for<'a> Ser<'a, T>: Serialize,
{
/// Consumes this wrapper, returning the inner value.
#[inline(always)]
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> fmt::Debug for Serde<T>
where T: fmt::Debug,
for<'de> De<T>: Deserialize<'de>,
for<'a> Ser<'a, T>: Serialize,
{
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
self.0.fmt(formatter)
}
}
impl<T> Deref for Serde<T>
where for<'de> De<T>: Deserialize<'de>,
for<'a> Ser<'a, T>: Serialize,
{
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T> DerefMut for Serde<T>
where for<'de> De<T>: Deserialize<'de>,
for<'a> Ser<'a, T>: Serialize,
{
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
impl<T: PartialEq> PartialEq<T> for Serde<T>
where for<'de> De<T>: Deserialize<'de>,
for<'a> Ser<'a, T>: Serialize,
{
fn eq(&self, other: &T) -> bool {
self.0 == *other
}
}
impl<'b, T> Deserialize<'b> for Serde<T>
where for<'de> De<T>: Deserialize<'de>,
for<'a> Ser<'a, T>: Serialize,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'b>,
{
De::deserialize(deserializer).map(De::into_inner).map(Serde)
}
}
impl<T> Serialize for Serde<T>
where for<'de> De<T>: Deserialize<'de>,
for<'a> Ser<'a, T>: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer,
{
Ser::new(&self.0).serialize(serializer)
}
}
impl<'de> Deserialize<'de> for De<ContentType> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>,
{
deserialize(deserializer).map(ContentType).map(De::new)
}
}
impl<'a> Serialize for Ser<'a, ContentType> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer,
{
serialize(&self.v.0, serializer)
}
}
impl<'de> Deserialize<'de> for De<Cookie<'static>> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>,
{
struct CookieVisitor;
impl<'de> Visitor<'de> for CookieVisitor {
type Value = De<Cookie<'static>>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "an HTTP cookie header value")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where E: de::Error,
{
Cookie::parse(v)
.map(Cookie::into_owned)
.map(De::new)
.map_err(|e| E::custom(format!("{:?}", e)))
}
}
deserializer.deserialize_string(CookieVisitor)
}
}
impl<'a, 'cookie> Serialize for Ser<'a, Cookie<'cookie>> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer,
{
serializer.serialize_str(&self.v.to_string())
}
}
impl<'de> Deserialize<'de> for De<Headers> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>,
{
struct HeadersVisitor;
impl<'de> Visitor<'de> for HeadersVisitor {
type Value = De<Headers>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a map from header names to header values")
}
fn visit_unit<E>(self) -> Result<Self::Value, E>
where E: de::Error,
{
Ok(De::new(Headers::new()))
}
fn visit_map<V>(self,
mut visitor: V)
-> Result<Self::Value, V::Error>
where V: MapAccess<'de>,
{
let mut headers = Headers::new();
while let Some((k, v)) = visitor.next_entry::<String, Value>()? {
headers.set_raw(k, v.0);
}
Ok(De::new(headers))
}
}
struct Value(Vec<Vec<u8>>);
impl<'de> Deserialize<'de> for Value {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>,
{
deserializer.deserialize_seq(ValueVisitor)
}
}
struct ValueVisitor;
impl<'de> Visitor<'de> for ValueVisitor {
type Value = Value;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "an array of strings and sequences of bytes")
}
fn visit_unit<E>(self) -> Result<Value, E>
where E: de::Error,
{
Ok(Value(vec![]))
}
fn visit_seq<V>(self, mut visitor: V) -> Result<Value, V::Error>
where V: SeqAccess<'de>,
{
// Clamp to not OOM on rogue values.
let capacity = cmp::min(visitor.size_hint().unwrap_or(0), 64);
let mut values = Vec::with_capacity(capacity);
while let Some(v) = visitor.next_element::<ByteBuf>()? {
values.push(v.into());
}
Ok(Value(values))
}
}
deserializer.deserialize_map(HeadersVisitor)
}
}
impl<'a> Serialize for Ser<'a, Headers> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer,
{
struct Value<'headers>(&'headers [Vec<u8>], bool);
impl<'headers> Serialize for Value<'headers> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer,
{
let mut serializer =
serializer.serialize_seq(Some(self.0.len()))?;
for v in self.0 {
if self.1 {
if let Ok(v) = str::from_utf8(v) {
serializer.serialize_element(v)?;
continue;
}
}
serializer.serialize_element(&Bytes::new(v))?;
}
serializer.end()
}
}
let mut serializer = serializer.serialize_map(Some(self.v.len()))?;
for header in self.v.iter() {
let name = header.name();
let value = self.v.get_raw(name).unwrap();
serializer.serialize_entry(name, &Value(value, self.pretty))?;
}
serializer.end()
}
}
impl<'de> Deserialize<'de> for De<Method> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>,
{
struct MethodVisitor;
impl<'de> Visitor<'de> for MethodVisitor {
type Value = De<Method>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "an HTTP method")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where E: de::Error,
{
v.parse::<Method>().map(De::new).map_err(E::custom)
}
}
deserializer.deserialize_string(MethodVisitor)
}
}
impl<'a> Serialize for Ser<'a, Method> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer,
{
Serialize::serialize(self.v.as_ref(), serializer)
}
}
impl<'de> Deserialize<'de> for De<Mime> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>,
{
struct MimeVisitor;
impl<'de> Visitor<'de> for MimeVisitor {
type Value = De<Mime>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a mime type")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where E: de::Error,
{
v.parse::<Mime>().map(De::new).map_err(|()| {
E::custom("could not parse mime type")
})
}
}
deserializer.deserialize_string(MimeVisitor)
}
}
impl<'a> Serialize for Ser<'a, Mime> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer,
{
serializer.serialize_str(&self.v.to_string())
}
}
impl<'de> Deserialize<'de> for De<RawStatus> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>,
{
let (code, reason) = Deserialize::deserialize(deserializer)?;
Ok(De::new(RawStatus(code, reason)))
}
}
impl<'a> Serialize for Ser<'a, RawStatus> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer,
{
(self.v.0, &self.v.1).serialize(serializer)
}
}
impl<'de> Deserialize<'de> for De<Tm> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>,
{
struct TmVisitor;
impl<'de> Visitor<'de> for TmVisitor {
type Value = De<Tm>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a date and time according to RFC 3339")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where E: de::Error,
{
strptime(v, "%Y-%m-%dT%H:%M:%SZ").map(De::new).map_err(|e| {
E::custom(e.to_string())
})
}
}
deserializer.deserialize_string(TmVisitor)
}
}
impl<'a> Serialize for Ser<'a, Tm> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer,
{
serializer.serialize_str(&self.v.rfc3339().to_string())
}
}

View File

@ -0,0 +1,33 @@
extern crate cookie;
extern crate hyper;
extern crate hyper_serde;
extern crate mime;
extern crate serde;
extern crate time;
use cookie::Cookie;
use hyper::header::{ContentType, Headers};
use hyper::http::RawStatus;
use hyper::method::Method;
use hyper_serde::{De, Ser, Serde};
use mime::Mime;
use serde::{Deserialize, Serialize};
use time::Tm;
fn is_supported<T>()
where for<'de> De<T>: Deserialize<'de>,
for<'a> Ser<'a, T>: Serialize,
for <'de> Serde<T>: Deserialize<'de> + Serialize
{
}
#[test]
fn supported() {
is_supported::<Cookie>();
is_supported::<ContentType>();
is_supported::<Headers>();
is_supported::<Method>();
is_supported::<Mime>();
is_supported::<RawStatus>();
is_supported::<Tm>();
}

View File

@ -0,0 +1,132 @@
extern crate cookie;
extern crate hyper;
extern crate hyper_serde;
#[macro_use]
extern crate mime;
extern crate serde;
extern crate serde_test;
extern crate time;
use cookie::Cookie;
use hyper::header::{ContentType, Headers};
use hyper::http::RawStatus;
use hyper::method::Method;
use hyper_serde::{De, Ser, deserialize};
use serde::Deserialize;
use serde_test::{Deserializer, Token, assert_ser_tokens};
use std::fmt::Debug;
use time::Duration;
#[test]
fn test_content_type() {
let content_type = ContentType(mime!(Application / Json));
let tokens = &[Token::Str("application/json")];
assert_ser_tokens(&Ser::new(&content_type), tokens);
assert_de_tokens(&content_type, tokens);
}
#[test]
fn test_cookie() {
let cookie = Cookie::build("Hello", "World!")
.max_age(Duration::seconds(42))
.domain("servo.org")
.path("/")
.secure(true)
.http_only(false)
.finish();
let tokens = &[Token::Str("Hello=World!; Secure; Path=/; \
Domain=servo.org; Max-Age=42")];
assert_ser_tokens(&Ser::new(&cookie), tokens);
assert_de_tokens(&cookie, tokens);
}
#[test]
fn test_headers_empty() {
let headers = Headers::new();
let tokens = &[Token::Map { len: Some(0) }, Token::MapEnd];
assert_ser_tokens(&Ser::new(&headers), tokens);
assert_de_tokens(&headers, tokens);
}
#[test]
fn test_headers_not_empty() {
use hyper::header::Host;
let mut headers = Headers::new();
headers.set(Host {
hostname: "baguette".to_owned(),
port: None,
});
// In Hyper 0.9, Headers is internally a HashMap and thus testing this
// with multiple headers is non-deterministic.
let tokens = &[Token::Map{ len: Some(1) },
Token::Str("Host"),
Token::Seq{ len: Some(1) },
Token::Bytes(b"baguette"),
Token::SeqEnd,
Token::MapEnd];
assert_ser_tokens(&Ser::new(&headers), tokens);
assert_de_tokens(&headers, tokens);
let pretty = &[Token::Map{ len: Some(1) },
Token::Str("Host"),
Token::Seq{ len: Some(1) },
Token::Str("baguette"),
Token::SeqEnd,
Token::MapEnd];
assert_ser_tokens(&Ser::new_pretty(&headers), pretty);
assert_de_tokens(&headers, pretty);
}
#[test]
fn test_method() {
let method = Method::Put;
let tokens = &[Token::Str("PUT")];
assert_ser_tokens(&Ser::new(&method), tokens);
assert_de_tokens(&method, tokens);
}
#[test]
fn test_raw_status() {
use std::borrow::Cow;
let raw_status = RawStatus(200, Cow::Borrowed("OK"));
let tokens = &[Token::Tuple{ len: 2 },
Token::U16(200),
Token::Str("OK"),
Token::TupleEnd];
assert_ser_tokens(&Ser::new(&raw_status), tokens);
assert_de_tokens(&raw_status, tokens);
}
#[test]
fn test_tm() {
use time::strptime;
let time = strptime("2017-02-22T12:03:31Z", "%Y-%m-%dT%H:%M:%SZ").unwrap();
let tokens = &[Token::Str("2017-02-22T12:03:31Z")];
assert_ser_tokens(&Ser::new(&time), tokens);
assert_de_tokens(&time, tokens);
}
pub fn assert_de_tokens<T>(value: &T, tokens: &[Token])
where T: Debug + PartialEq,
for<'de> De<T>: Deserialize<'de>,
{
let mut deserializer = Deserializer::new(&tokens);
let v = deserialize::<T, _>(&mut deserializer).unwrap();
assert_eq!(&v, value);
assert_eq!(deserializer.next_token_opt(), None);
}

View File

@ -0,0 +1 @@
{"files":{"Cargo.toml":"acd21fe58d1af762230c1dec07b9e0131d65b1751f5e5d0aebb7cd6f79f56720","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"f0b7988c93ab594ca02b313b312b97a4c83669cd31aa0705711c113052130144","src/lib.rs":"cc5ff1cc84363022ac02e7291976b8d8d679cf5fbd021f192570c59e4011ddbd","src/value.rs":"911090aa5f4b0ee7ea00a8fe9d72e4df33dd4d9017689f0bdf97fa3a3d267817"},"package":"adb6e51a6b3696b301bc221d785f898b4457c619b51d7ce195a6d20baecb37b3"}

41
third_party/rust/serde_bytes/Cargo.toml vendored Normal file
View File

@ -0,0 +1,41 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g. crates.io) dependencies
#
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
[package]
name = "serde_bytes"
version = "0.10.4"
authors = ["David Tolnay <dtolnay@gmail.com>"]
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
description = "Optimized handling of `&[u8]` and `Vec<u8>` for Serde"
homepage = "https://serde.rs"
documentation = "https://docs.serde.rs/serde_bytes/"
readme = "README.md"
keywords = ["serde", "serialization", "no_std"]
categories = ["encoding"]
license = "MIT/Apache-2.0"
repository = "https://github.com/serde-rs/bytes"
[dependencies.serde]
version = "1.0"
default-features = false
[dev-dependencies.bincode]
version = "0.8"
[dev-dependencies.serde_derive]
version = "1.0"
[dev-dependencies.serde_test]
version = "1.0"
[features]
alloc = ["serde/alloc"]
default = ["std"]
std = ["serde/std"]

View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,25 @@
Copyright (c) 2014 The Rust Project Developers
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

55
third_party/rust/serde_bytes/README.md vendored Normal file
View File

@ -0,0 +1,55 @@
# serde\_bytes [![Build Status](https://api.travis-ci.org/serde-rs/bytes.svg?branch=master)](https://travis-ci.org/serde-rs/bytes) [![Latest Version](https://img.shields.io/crates/v/serde_bytes.svg)](https://crates.io/crates/serde_bytes)
Wrapper types to enable optimized handling of `&[u8]` and `Vec<u8>`.
Without specialization, Rust forces Serde to treat `&[u8]` just like any
other slice and `Vec<u8>` just like any other vector. In reality this
particular slice and vector can often be serialized and deserialized in a
more efficient, compact representation in many formats.
When working with such a format, you can opt into specialized handling of
`&[u8]` by wrapping it in `serde_bytes::Bytes` and `Vec<u8>` by wrapping it
in `serde_bytes::ByteBuf`.
This crate supports the Serde `with` attribute to enable efficient handling
of `&[u8]` and `Vec<u8>` in structs without needing a wrapper type.
```rust
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_bytes;
#[derive(Serialize)]
struct Efficient<'a> {
#[serde(with = "serde_bytes")]
bytes: &'a [u8],
#[serde(with = "serde_bytes")]
byte_buf: Vec<u8>,
}
#[derive(Serialize, Deserialize)]
struct Packet {
#[serde(with = "serde_bytes")]
payload: Vec<u8>,
}
```
## License
Serde is licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
http://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.

431
third_party/rust/serde_bytes/src/lib.rs vendored Normal file
View File

@ -0,0 +1,431 @@
//! Wrapper types to enable optimized handling of `&[u8]` and `Vec<u8>`.
//!
//! Without specialization, Rust forces Serde to treat `&[u8]` just like any
//! other slice and `Vec<u8>` just like any other vector. In reality this
//! particular slice and vector can often be serialized and deserialized in a
//! more efficient, compact representation in many formats.
//!
//! When working with such a format, you can opt into specialized handling of
//! `&[u8]` by wrapping it in `serde_bytes::Bytes` and `Vec<u8>` by wrapping it
//! in `serde_bytes::ByteBuf`.
//!
//! This crate supports the Serde `with` attribute to enable efficient handling
//! of `&[u8]` and `Vec<u8>` in structs without needing a wrapper type.
//!
//! ```rust
//! #[macro_use]
//! extern crate serde_derive;
//!
//! extern crate serde;
//! extern crate serde_bytes;
//!
//! #[derive(Serialize)]
//! struct Efficient<'a> {
//! #[serde(with = "serde_bytes")]
//! bytes: &'a [u8],
//!
//! #[serde(with = "serde_bytes")]
//! byte_buf: Vec<u8>,
//! }
//!
//! #[derive(Serialize, Deserialize)]
//! struct Packet {
//! #[serde(with = "serde_bytes")]
//! payload: Vec<u8>,
//! }
//! #
//! # fn main() {}
//! ```
#![doc(html_root_url = "https://docs.rs/serde_bytes/0.10.4")]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "alloc", feature(alloc))]
#![deny(missing_docs)]
#[cfg(feature = "std")]
use std::{fmt, ops};
#[cfg(not(feature = "std"))]
use core::{fmt, ops};
use self::fmt::Debug;
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::Vec;
#[macro_use]
extern crate serde;
use serde::ser::{Serialize, Serializer};
use serde::de::{Deserialize, Deserializer, Visitor, Error};
#[cfg(any(feature = "std", feature = "alloc"))]
pub use self::bytebuf::ByteBuf;
mod value;
//////////////////////////////////////////////////////////////////////////////
/// Serde `serialize_with` function to serialize bytes efficiently.
///
/// This function can be used with either of the following Serde attributes:
///
/// - `#[serde(with = "serde_bytes")]`
/// - `#[serde(serialize_with = "serde_bytes::serialize")]`
///
/// ```rust
/// #[macro_use]
/// extern crate serde_derive;
///
/// extern crate serde;
/// extern crate serde_bytes;
///
/// #[derive(Serialize)]
/// struct Efficient<'a> {
/// #[serde(with = "serde_bytes")]
/// bytes: &'a [u8],
///
/// #[serde(with = "serde_bytes")]
/// byte_buf: Vec<u8>,
/// }
/// #
/// # fn main() {}
/// ```
pub fn serialize<T, S>(bytes: &T, serializer: S) -> Result<S::Ok, S::Error>
where T: ?Sized + AsRef<[u8]>,
S: Serializer
{
serializer.serialize_bytes(bytes.as_ref())
}
/// Serde `deserialize_with` function to deserialize bytes efficiently.
///
/// This function can be used with either of the following Serde attributes:
///
/// - `#[serde(with = "serde_bytes")]`
/// - `#[serde(deserialize_with = "serde_bytes::deserialize")]`
///
/// ```rust
/// #[macro_use]
/// extern crate serde_derive;
///
/// extern crate serde;
/// extern crate serde_bytes;
///
/// #[derive(Deserialize)]
/// struct Packet {
/// #[serde(with = "serde_bytes")]
/// payload: Vec<u8>,
/// }
/// #
/// # fn main() {}
/// ```
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
where T: From<Vec<u8>>,
D: Deserializer<'de>
{
ByteBuf::deserialize(deserializer).map(|buf| Into::<Vec<u8>>::into(buf).into())
}
//////////////////////////////////////////////////////////////////////////////
/// Wrapper around `&[u8]` to serialize and deserialize efficiently.
///
/// ```rust
/// extern crate bincode;
/// extern crate serde_bytes;
///
/// use std::collections::HashMap;
/// use std::io;
///
/// use serde_bytes::Bytes;
///
/// fn print_encoded_cache() -> Result<(), bincode::Error> {
/// let mut cache = HashMap::new();
/// cache.insert(3, Bytes::new(b"three"));
/// cache.insert(2, Bytes::new(b"two"));
/// cache.insert(1, Bytes::new(b"one"));
///
/// bincode::serialize_into(&mut io::stdout(), &cache, bincode::Infinite)
/// }
/// #
/// # fn main() {
/// # print_encoded_cache().unwrap();
/// # }
/// ```
#[derive(Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct Bytes<'a> {
bytes: &'a [u8],
}
impl<'a> Bytes<'a> {
/// Wrap an existing `&[u8]`.
pub fn new(bytes: &'a [u8]) -> Self {
Bytes { bytes: bytes }
}
}
impl<'a> Debug for Bytes<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Debug::fmt(self.bytes, f)
}
}
impl<'a> From<&'a [u8]> for Bytes<'a> {
fn from(bytes: &'a [u8]) -> Self {
Bytes::new(bytes)
}
}
impl<'a> From<Bytes<'a>> for &'a [u8] {
fn from(wrapper: Bytes<'a>) -> &'a [u8] {
wrapper.bytes
}
}
impl<'a> ops::Deref for Bytes<'a> {
type Target = [u8];
fn deref(&self) -> &[u8] {
self.bytes
}
}
impl<'a> Serialize for Bytes<'a> {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
serializer.serialize_bytes(self.bytes)
}
}
struct BytesVisitor;
impl<'de> Visitor<'de> for BytesVisitor {
type Value = Bytes<'de>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a borrowed byte array")
}
#[inline]
fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Bytes<'de>, E>
where E: Error
{
Ok(Bytes::from(v))
}
#[inline]
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Bytes<'de>, E>
where E: Error
{
Ok(Bytes::from(v.as_bytes()))
}
}
impl<'a, 'de: 'a> Deserialize<'de> for Bytes<'a> {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Bytes<'a>, D::Error>
where D: Deserializer<'de>
{
deserializer.deserialize_bytes(BytesVisitor)
}
}
//////////////////////////////////////////////////////////////////////////////
#[cfg(any(feature = "std", feature = "alloc"))]
mod bytebuf {
#[cfg(feature = "std")]
use std::{cmp, fmt, ops};
#[cfg(not(feature = "std"))]
use core::{cmp, fmt, ops};
use self::fmt::Debug;
#[cfg(feature = "alloc")]
use alloc::{String, Vec};
use serde::ser::{Serialize, Serializer};
use serde::de::{Deserialize, Deserializer, Visitor, SeqAccess, Error};
/// Wrapper around `Vec<u8>` to serialize and deserialize efficiently.
///
/// ```rust
/// extern crate bincode;
/// extern crate serde_bytes;
///
/// use std::collections::HashMap;
/// use std::io;
///
/// use serde_bytes::ByteBuf;
///
/// fn deserialize_bytebufs() -> Result<(), bincode::Error> {
/// let example_data = [
/// 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 116,
/// 119, 111, 1, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 111, 110, 101];
///
/// let map: HashMap<u32, ByteBuf> =
/// bincode::deserialize_from(&mut &example_data[..], bincode::Infinite)?;
///
/// println!("{:?}", map);
///
/// Ok(())
/// }
/// #
/// # fn main() {
/// # deserialize_bytebufs().unwrap();
/// # }
/// ```
#[derive(Clone, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct ByteBuf {
bytes: Vec<u8>,
}
impl ByteBuf {
/// Construct a new, empty `ByteBuf`.
pub fn new() -> Self {
ByteBuf::from(Vec::new())
}
/// Construct a new, empty `ByteBuf` with the specified capacity.
pub fn with_capacity(cap: usize) -> Self {
ByteBuf::from(Vec::with_capacity(cap))
}
/// Wrap existing bytes in a `ByteBuf`.
pub fn from<T: Into<Vec<u8>>>(bytes: T) -> Self {
ByteBuf { bytes: bytes.into() }
}
}
impl Debug for ByteBuf {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Debug::fmt(&self.bytes, f)
}
}
impl From<ByteBuf> for Vec<u8> {
fn from(wrapper: ByteBuf) -> Vec<u8> {
wrapper.bytes
}
}
impl From<Vec<u8>> for ByteBuf {
fn from(bytes: Vec<u8>) -> Self {
ByteBuf::from(bytes)
}
}
impl AsRef<Vec<u8>> for ByteBuf {
fn as_ref(&self) -> &Vec<u8> {
&self.bytes
}
}
impl AsRef<[u8]> for ByteBuf {
fn as_ref(&self) -> &[u8] {
&self.bytes
}
}
impl AsMut<Vec<u8>> for ByteBuf {
fn as_mut(&mut self) -> &mut Vec<u8> {
&mut self.bytes
}
}
impl AsMut<[u8]> for ByteBuf {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.bytes
}
}
impl ops::Deref for ByteBuf {
type Target = [u8];
fn deref(&self) -> &[u8] {
&self.bytes[..]
}
}
impl ops::DerefMut for ByteBuf {
fn deref_mut(&mut self) -> &mut [u8] {
&mut self.bytes[..]
}
}
impl Serialize for ByteBuf {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
serializer.serialize_bytes(&self.bytes)
}
}
struct ByteBufVisitor;
impl<'de> Visitor<'de> for ByteBufVisitor {
type Value = ByteBuf;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("byte array")
}
#[inline]
fn visit_seq<V>(self, mut visitor: V) -> Result<ByteBuf, V::Error>
where V: SeqAccess<'de>
{
let len = cmp::min(visitor.size_hint().unwrap_or(0), 4096);
let mut values = Vec::with_capacity(len);
while let Some(value) = try!(visitor.next_element()) {
values.push(value);
}
Ok(ByteBuf::from(values))
}
#[inline]
fn visit_bytes<E>(self, v: &[u8]) -> Result<ByteBuf, E>
where E: Error
{
Ok(ByteBuf::from(v))
}
#[inline]
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<ByteBuf, E>
where E: Error
{
Ok(ByteBuf::from(v))
}
#[inline]
fn visit_str<E>(self, v: &str) -> Result<ByteBuf, E>
where E: Error
{
Ok(ByteBuf::from(v))
}
#[inline]
fn visit_string<E>(self, v: String) -> Result<ByteBuf, E>
where E: Error
{
Ok(ByteBuf::from(v))
}
}
impl<'de> Deserialize<'de> for ByteBuf {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<ByteBuf, D::Error>
where D: Deserializer<'de>
{
deserializer.deserialize_byte_buf(ByteBufVisitor)
}
}
}

View File

@ -0,0 +1,91 @@
use serde::de::{Deserializer, IntoDeserializer, Visitor, Error};
#[cfg(feature = "std")]
use std::marker::PhantomData;
#[cfg(not(feature = "std"))]
use core::marker::PhantomData;
#[cfg(feature = "alloc")]
use alloc::Vec;
//////////////////////////////////////////////////////////////////////////////
impl<'de, 'a, E> IntoDeserializer<'de, E> for super::Bytes<'a>
where E: Error
{
type Deserializer = BytesDeserializer<'a, E>;
fn into_deserializer(self) -> Self::Deserializer {
BytesDeserializer {
value: self.into(),
error: PhantomData,
}
}
}
/// A deserializer that deserializes a `&[u8]`.
pub struct BytesDeserializer<'a, E> {
value: &'a [u8],
error: PhantomData<E>,
}
impl<'de, 'a, E> Deserializer<'de> for BytesDeserializer<'a, E>
where E: Error
{
type Error = E;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where V: Visitor<'de>
{
visitor.visit_bytes(self.value)
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any
}
}
//////////////////////////////////////////////////////////////////////////////
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de, E> IntoDeserializer<'de, E> for super::ByteBuf
where E: Error
{
type Deserializer = ByteBufDeserializer<E>;
fn into_deserializer(self) -> Self::Deserializer {
ByteBufDeserializer {
value: self.into(),
error: PhantomData,
}
}
}
/// A deserializer that deserializes a `Vec<u8>`.
#[cfg(any(feature = "std", feature = "alloc"))]
pub struct ByteBufDeserializer<E> {
value: Vec<u8>,
error: PhantomData<E>,
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'de, E> Deserializer<'de> for ByteBufDeserializer<E>
where E: Error
{
type Error = E;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where V: Visitor<'de>
{
visitor.visit_byte_buf(self.value)
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any
}
}