Diff
Modified: trunk/Source/WebCore/ChangeLog (142625 => 142626)
--- trunk/Source/WebCore/ChangeLog 2013-02-12 15:53:48 UTC (rev 142625)
+++ trunk/Source/WebCore/ChangeLog 2013-02-12 15:56:28 UTC (rev 142626)
@@ -1,3 +1,59 @@
+2013-02-12 Yury Semikhatsky <yu...@chromium.org>
+
+ Web Inspector: add initial implementation of native memory graph to Timeline
+ https://bugs.webkit.org/show_bug.cgi?id=109578
+
+ Reviewed by Alexander Pavlov.
+
+ This change adds inital implementation of native memory graph UI. The graph
+ will be shown in the same place as DOM counters graph on the Timeline panel.
+
+ Added NativeMemoryGraph.js that reuses parts of DOM counters graph
+ implementation. MemoryStatistics.js was refactor to allow sharing
+ more code between DOM counters and native memory graph.
+
+ * WebCore.gypi:
+ * WebCore.vcproj/WebCore.vcproj:
+ * inspector/compile-front-end.py:
+ * inspector/front-end/MemoryStatistics.js:
+ (WebInspector.MemoryStatistics):
+ (WebInspector.MemoryStatistics.prototype._createCurrentValuesBar):
+ (WebInspector.MemoryStatistics.prototype._createCounterUIList):
+ (WebInspector.MemoryStatistics.prototype._createCounterUIList.getNodeCount):
+ (WebInspector.MemoryStatistics.prototype._createCounterUIList.getListenerCount):
+ (WebInspector.MemoryStatistics.prototype._canvasHeight):
+ (WebInspector.MemoryStatistics.prototype._updateSize):
+ (WebInspector.MemoryStatistics.prototype._highlightCurrentPositionOnGraphs):
+ (WebInspector.MemoryStatistics.prototype._drawMarker):
+ * inspector/front-end/NativeMemoryGraph.js: Added.
+ (WebInspector.NativeMemoryGraph):
+ (WebInspector.NativeMemoryCounterUI):
+ (WebInspector.NativeMemoryCounterUI.prototype._hslToString):
+ (WebInspector.NativeMemoryCounterUI.prototype.updateCurrentValue):
+ (WebInspector.NativeMemoryCounterUI.prototype.clearCurrentValueAndMarker):
+ (WebInspector.NativeMemoryGraph.prototype._createCurrentValuesBar):
+ (WebInspector.NativeMemoryGraph.prototype._createCounterUIList.getCounterValue):
+ (WebInspector.NativeMemoryGraph.prototype._createCounterUIList):
+ (WebInspector.NativeMemoryGraph.prototype._canvasHeight):
+ (WebInspector.NativeMemoryGraph.prototype._onRecordAdded.addStatistics):
+ (WebInspector.NativeMemoryGraph.prototype._onRecordAdded):
+ (WebInspector.NativeMemoryGraph.prototype._draw):
+ (WebInspector.NativeMemoryGraph.prototype._clearCurrentValueAndMarker):
+ (WebInspector.NativeMemoryGraph.prototype._updateCurrentValue):
+ (WebInspector.NativeMemoryGraph.prototype._restoreImageUnderMarker):
+ (WebInspector.NativeMemoryGraph.prototype._saveImageUnderMarker):
+ (WebInspector.NativeMemoryGraph.prototype._drawMarker):
+ (WebInspector.NativeMemoryGraph.prototype._maxCounterValue):
+ (WebInspector.NativeMemoryGraph.prototype._resetTotalValues):
+ (WebInspector.NativeMemoryGraph.prototype.valueGetter):
+ (WebInspector.NativeMemoryGraph.prototype._drawGraph):
+ (WebInspector.NativeMemoryGraph.prototype._discardImageUnderMarker):
+ * inspector/front-end/TimelinePanel.js:
+ * inspector/front-end/WebKit.qrc:
+ * inspector/front-end/timelinePanel.css:
+ (#memory-graphs-canvas-container.dom-counters .resources-dividers):
+ (.memory-category-value):
+
2013-02-12 Andrey Lushnikov <lushni...@chromium.org>
Web Inspector: refactor some reusable functionality from BraceHighlighter
Modified: trunk/Source/WebCore/WebCore.gypi (142625 => 142626)
--- trunk/Source/WebCore/WebCore.gypi 2013-02-12 15:53:48 UTC (rev 142625)
+++ trunk/Source/WebCore/WebCore.gypi 2013-02-12 15:56:28 UTC (rev 142626)
@@ -5392,6 +5392,7 @@
],
'webinspector_timeline_js_files': [
'inspector/front-end/MemoryStatistics.js',
+ 'inspector/front-end/NativeMemoryGraph.js',
'inspector/front-end/TimelineFrameController.js',
'inspector/front-end/TimelineModel.js',
'inspector/front-end/TimelinePresentationModel.js',
Modified: trunk/Source/WebCore/WebCore.vcproj/WebCore.vcproj (142625 => 142626)
--- trunk/Source/WebCore/WebCore.vcproj/WebCore.vcproj 2013-02-12 15:53:48 UTC (rev 142625)
+++ trunk/Source/WebCore/WebCore.vcproj/WebCore.vcproj 2013-02-12 15:56:28 UTC (rev 142626)
@@ -77330,6 +77330,10 @@
>
</File>
<File
+ RelativePath="..\inspector\front-end\MemoryStatistics.js"
+ >
+ </File>
+ <File
RelativePath="..\inspector\front-end\MetricsSidebarPane.js"
>
</File>
@@ -77342,6 +77346,10 @@
>
</File>
<File
+ RelativePath="..\inspector\front-end\NativeMemoryGraph.js"
+ >
+ </File>
+ <File
RelativePath="..\inspector\front-end\nativeMemoryProfiler.css"
>
</File>
Modified: trunk/Source/WebCore/inspector/compile-front-end.py (142625 => 142626)
--- trunk/Source/WebCore/inspector/compile-front-end.py 2013-02-12 15:53:48 UTC (rev 142625)
+++ trunk/Source/WebCore/inspector/compile-front-end.py 2013-02-12 15:56:28 UTC (rev 142626)
@@ -278,6 +278,7 @@
"dependencies": ["components"],
"sources": [
"MemoryStatistics.js",
+ "NativeMemoryGraph.js",
"TimelineModel.js",
"TimelineOverviewPane.js",
"TimelinePanel.js",
Modified: trunk/Source/WebCore/inspector/front-end/MemoryStatistics.js (142625 => 142626)
--- trunk/Source/WebCore/inspector/front-end/MemoryStatistics.js 2013-02-12 15:53:48 UTC (rev 142625)
+++ trunk/Source/WebCore/inspector/front-end/MemoryStatistics.js 2013-02-12 15:56:28 UTC (rev 142626)
@@ -51,8 +51,7 @@
this._canvasContainer = this._memorySidebarView.mainElement;
this._canvasContainer.id = "memory-graphs-canvas-container";
- this._currentValuesBar = this._canvasContainer.createChild("div");
- this._currentValuesBar.id = "counter-values-bar";
+ this._createCurrentValuesBar();
this._canvas = this._canvasContainer.createChild("canvas");
this._canvas.id = "memory-counters-graph";
this._lastMarkerXPosition = 0;
@@ -67,23 +66,7 @@
// Populate sidebar
this._memorySidebarView.sidebarElement.createChild("div", "sidebar-tree sidebar-tree-section").textContent = WebInspector.UIString("COUNTERS");
- function getDocumentCount(entry)
- {
- return entry.documentCount;
- }
- function getNodeCount(entry)
- {
- return entry.nodeCount;
- }
- function getListenerCount(entry)
- {
- return entry.listenerCount;
- }
- this._counterUI = [
- new WebInspector.DOMCounterUI(this, "Document Count", "Documents: %d", [100,0,0], getDocumentCount),
- new WebInspector.DOMCounterUI(this, "DOM Node Count", "Nodes: %d", [0,100,0], getNodeCount),
- new WebInspector.DOMCounterUI(this, "Event Listener Count", "Listeners: %d", [0,0,100], getListenerCount)
- ];
+ this._counterUI = this._createCounterUIList();
TimelineAgent.setIncludeMemoryDetails(true);
}
@@ -240,6 +223,34 @@
WebInspector.MemoryStatistics.prototype = {
+ _createCurrentValuesBar: function()
+ {
+ this._currentValuesBar = this._canvasContainer.createChild("div");
+ this._currentValuesBar.id = "counter-values-bar";
+ this._canvasContainer.addStyleClass("dom-counters");
+ },
+
+ _createCounterUIList: function()
+ {
+ function getDocumentCount(entry)
+ {
+ return entry.documentCount;
+ }
+ function getNodeCount(entry)
+ {
+ return entry.nodeCount;
+ }
+ function getListenerCount(entry)
+ {
+ return entry.listenerCount;
+ }
+ return [
+ new WebInspector.DOMCounterUI(this, "Document Count", "Documents: %d", [100,0,0], getDocumentCount),
+ new WebInspector.DOMCounterUI(this, "DOM Node Count", "Nodes: %d", [0,100,0], getNodeCount),
+ new WebInspector.DOMCounterUI(this, "Event Listener Count", "Listeners: %d", [0,0,100], getListenerCount)
+ ];
+ },
+
_onRecordsCleared: function()
{
this._counters = [];
@@ -274,12 +285,17 @@
this._ignoreSidebarResize = false;
},
+ _canvasHeight: function()
+ {
+ return this._canvasContainer.offsetHeight - this._currentValuesBar.offsetHeight;
+ },
+
_updateSize: function()
{
var width = this._mainTimelineGrid.dividersElement.offsetWidth + 1;
this._canvasContainer.style.width = width + "px";
- var height = this._canvasContainer.offsetHeight - this._currentValuesBar.offsetHeight;
+ var height = this._canvasHeight();
this._canvas.width = width;
this._canvas.height = height;
},
@@ -411,7 +427,6 @@
{
var ctx = this._canvas.getContext("2d");
this._restoreImageUnderMarker(ctx);
- this._saveImageUnderMarker(ctx, x, index);
this._drawMarker(ctx, x, index);
},
@@ -439,6 +454,7 @@
_drawMarker: function(ctx, x, index)
{
+ this._saveImageUnderMarker(ctx, x, index);
const radius = 2;
for (var i = 0; i < this._counterUI.length; i++) {
var counterUI = this._counterUI[i];
Added: trunk/Source/WebCore/inspector/front-end/NativeMemoryGraph.js (0 => 142626)
--- trunk/Source/WebCore/inspector/front-end/NativeMemoryGraph.js (rev 0)
+++ trunk/Source/WebCore/inspector/front-end/NativeMemoryGraph.js 2013-02-12 15:56:28 UTC (rev 142626)
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @param {WebInspector.TimelinePanel} timelinePanel
+ * @param {WebInspector.TimelineModel} model
+ * @param {number} sidebarWidth
+ * @constructor
+ * @extends {WebInspector.MemoryStatistics}
+ */
+WebInspector.NativeMemoryGraph = function(timelinePanel, model, sidebarWidth)
+{
+ WebInspector.MemoryStatistics.call(this, timelinePanel, model, sidebarWidth);
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.CounterUIBase}
+ */
+WebInspector.NativeMemoryCounterUI = function(memoryCountersPane, title, hsl, valueGetter)
+{
+ var swatchColor = this._hslToString(hsl);
+ WebInspector.CounterUIBase.call(this, memoryCountersPane, title, swatchColor, valueGetter);
+ this._value = this._swatch.element.createChild("span", "memory-category-value");
+
+ const borderLightnessDifference = 3;
+ hsl[2] -= borderLightnessDifference;
+ this.strokeColor = this._hslToString(hsl);
+ this.graphYValues = [];
+}
+
+WebInspector.NativeMemoryCounterUI.prototype = {
+ _hslToString: function(hsl)
+ {
+ return "hsl(" + hsl[0] + "," + hsl[1] + "%," + hsl[2] + "%)";
+ },
+
+ updateCurrentValue: function(countersEntry)
+ {
+ this._value.textContent = Number.bytesToString(this.valueGetter(countersEntry));
+ },
+
+ clearCurrentValueAndMarker: function(ctx)
+ {
+ this._value.textContent = "";
+ },
+
+ __proto__: WebInspector.CounterUIBase.prototype
+}
+
+
+WebInspector.NativeMemoryGraph.prototype = {
+ _createCurrentValuesBar: function()
+ {
+ },
+
+ _createCounterUIList: function()
+ {
+ var nativeCounters = [
+ "JSExternalResources",
+ "CSS",
+ "GlyphCache",
+ "Image",
+ "Resources",
+ "DOM",
+ "Rendering",
+ "Audio",
+ "WebInspector",
+ "JSHeap.Used",
+ "JSHeap.Unused",
+ "MallocWaste",
+ "Other",
+ "PrivateBytes",
+ ];
+
+ /**
+ * @param {string} name
+ * @return {number}
+ */
+ function getCounterValue(name, entry)
+ {
+ return (entry.nativeCounters && entry.nativeCounters[name]) || 0;
+ }
+
+ var list = [];
+ for (var i = nativeCounters.length - 1; i >= 0; i--) {
+ var name = nativeCounters[i];
+ if ("PrivateBytes" === name) {
+ var counterUI = new WebInspector.NativeMemoryCounterUI(this, "Total", [0, 0, 0], getCounterValue.bind(this, name))
+ this._privateBytesCounter = counterUI;
+ } else {
+ var counterUI = new WebInspector.NativeMemoryCounterUI(this, name, [i * 20, 65, 63], getCounterValue.bind(this, name))
+ list.push(counterUI);
+ }
+ }
+ return list.reverse();
+ },
+
+ _canvasHeight: function()
+ {
+ return this._canvasContainer.offsetHeight;
+ },
+
+ /**
+ * @param {WebInspector.Event} event
+ */
+ _onRecordAdded: function(event)
+ {
+ var statistics = this._counters;
+ function addStatistics(record)
+ {
+ var counters = record["counters"];
+ if (!counters)
+ return;
+ var nativeCounters = counters["native"];
+ if (!nativeCounters)
+ return;
+
+ var knownSize = 0;
+ for (var name in nativeCounters) {
+ if (name === "PrivateBytes")
+ continue;
+ knownSize += nativeCounters[name];
+ }
+ nativeCounters["Other"] = nativeCounters["PrivateBytes"] - knownSize;
+
+ statistics.push({
+ time: record.endTime || record.startTime,
+ nativeCounters: nativeCounters
+ });
+ }
+ WebInspector.TimelinePresentationModel.forAllRecords([event.data], null, addStatistics);
+ },
+
+ _draw: function()
+ {
+ this._calculateVisibleIndexes();
+ this._calculateXValues();
+ this._clear();
+
+ this._setVerticalClip(10, this._canvas.height - 20);
+
+ var maxValue = this._maxCounterValue();
+ this._resetTotalValues();
+
+ var previousCounterUI;
+ for (var i = 0; i < this._counterUI.length; i++) {
+ this._drawGraph(this._counterUI[i], previousCounterUI, maxValue);
+ if (this._counterUI[i].visible)
+ previousCounterUI = this._counterUI[i];
+ }
+ },
+
+ /**
+ * @param {CanvasRenderingContext2D} ctx
+ */
+ _clearCurrentValueAndMarker: function(ctx)
+ {
+ WebInspector.MemoryStatistics.prototype._clearCurrentValueAndMarker.call(this, ctx);
+ this._privateBytesCounter.clearCurrentValueAndMarker(ctx);
+ },
+
+ _updateCurrentValue: function(counterEntry)
+ {
+ WebInspector.MemoryStatistics.prototype._updateCurrentValue.call(this, counterEntry);
+ this._privateBytesCounter.updateCurrentValue(counterEntry);
+ },
+
+ /**
+ * @param {CanvasRenderingContext2D} ctx
+ */
+ _restoreImageUnderMarker: function(ctx)
+ {
+ if (this._imageUnderMarker)
+ ctx.putImageData(this._imageUnderMarker.imageData, this._imageUnderMarker.x, this._imageUnderMarker.y);
+ this._discardImageUnderMarker();
+ },
+
+ /**
+ * @param {CanvasRenderingContext2D} ctx
+ * @param {number} left
+ * @param {number} top
+ * @param {number} right
+ * @param {number} bottom
+ */
+ _saveImageUnderMarker: function(ctx, left, top, right, bottom)
+ {
+ var imageData = ctx.getImageData(left, top, right, bottom);
+ this._imageUnderMarker = {
+ x: left,
+ y: top,
+ imageData: imageData
+ };
+ },
+
+ /**
+ * @param {CanvasRenderingContext2D} ctx
+ * @param {number} x
+ * @param {number} index
+ */
+ _drawMarker: function(ctx, x, index)
+ {
+ var left = this._counters[index].x;
+ var right = index + 1 < this._counters.length ? this._counters[index + 1].x : left;
+ var top = this._originY;
+ top = 0;
+ var bottom = top + this._clippedHeight;
+ bottom += this._originY;
+
+ this._saveImageUnderMarker(ctx, left, top, right, bottom);
+
+ ctx.beginPath();
+ ctx.moveTo(left, top);
+ ctx.lineTo(right, top);
+ ctx.lineTo(right, bottom);
+ ctx.lineTo(left, bottom);
+ ctx.lineWidth = 1;
+ ctx.closePath();
+ ctx.fillStyle = "rgba(220,220,220,0.3)";
+ ctx.fill();
+ },
+
+ /**
+ * @return {number}
+ */
+ _maxCounterValue: function()
+ {
+ if (!this._counters.length)
+ return 0;
+
+ var valueGetter = this._privateBytesCounter.valueGetter;
+ var result = 0;
+ for (var i = this._minimumIndex; i < this._maximumIndex; i++) {
+ var counter = this._counters[i];
+ var value = valueGetter(counter);
+ if (value > result)
+ result = value;
+ }
+ return result;
+ },
+
+ _resetTotalValues: function()
+ {
+ for (var i = this._minimumIndex; i <= this._maximumIndex; i++) {
+ var counter = this._counters[i];
+ counter.total = 0;
+ }
+ },
+
+ /**
+ * @param {WebInspector.CounterUIBase} counterUI
+ * @param {WebInspector.CounterUIBase} previousCounterUI
+ * @param {number} maxTotalValue
+ */
+ _drawGraph: function(counterUI, previousCounterUI, maxTotalValue)
+ {
+ var canvas = this._canvas;
+ var ctx = canvas.getContext("2d");
+ var width = canvas.width;
+ var height = this._clippedHeight;
+ var originY = this._originY;
+ var valueGetter = counterUI.valueGetter;
+
+ if (!this._counters.length)
+ return;
+
+ if (!counterUI.visible)
+ return;
+
+ for (var i = this._minimumIndex; i <= this._maximumIndex; i++) {
+ var counter = this._counters[i];
+ var value = valueGetter(counter);
+ counter.total += value;
+ }
+
+ var yValues = counterUI.graphYValues;
+ yValues.length = this._counters.length;
+
+ var maxYRange = maxTotalValue;
+ var yFactor = maxYRange ? height / (maxYRange) : 1;
+
+ ctx.beginPath();
+ if (previousCounterUI) {
+ var prevYValues = previousCounterUI.graphYValues;
+ var currentY = prevYValues[this._maximumIndex];
+ ctx.moveTo(width, currentY);
+ var currentX = width;
+ for (var i = this._maximumIndex - 1; i >= this._minimumIndex; i--) {
+ currentY = prevYValues[i];
+ currentX = this._counters[i].x;
+ ctx.lineTo(currentX, currentY);
+ }
+ } else {
+ var lastY = originY + height;
+ ctx.moveTo(width, lastY);
+ ctx.lineTo(0, lastY);
+ }
+
+ var currentY = originY + (height - this._counters[this._minimumIndex].total * yFactor);
+ ctx.lineTo(0, currentY);
+ for (var i = this._minimumIndex; i <= this._maximumIndex; i++) {
+ var counter = this._counters[i];
+ var x = counter.x;
+ currentY = originY + (height - counter.total * yFactor);
+ ctx.lineTo(x, currentY);
+
+ yValues[i] = currentY;
+ }
+ ctx.lineTo(width, currentY);
+ ctx.closePath();
+ ctx.lineWidth = 1;
+
+ ctx.strokeStyle = counterUI.strokeColor;
+ ctx.fillStyle = counterUI.graphColor;
+ ctx.fill();
+ ctx.stroke();
+ },
+
+ _discardImageUnderMarker: function()
+ {
+ delete this._imageUnderMarker;
+ },
+
+ __proto__: WebInspector.MemoryStatistics.prototype
+}
+
Property changes on: trunk/Source/WebCore/inspector/front-end/NativeMemoryGraph.js
___________________________________________________________________
Added: svn:eol-style
Modified: trunk/Source/WebCore/inspector/front-end/TimelinePanel.js (142625 => 142626)
--- trunk/Source/WebCore/inspector/front-end/TimelinePanel.js 2013-02-12 15:53:48 UTC (rev 142625)
+++ trunk/Source/WebCore/inspector/front-end/TimelinePanel.js 2013-02-12 15:56:28 UTC (rev 142626)
@@ -30,6 +30,7 @@
*/
importScript("MemoryStatistics.js");
+importScript("NativeMemoryGraph.js");
importScript("TimelineModel.js");
importScript("TimelineOverviewPane.js");
importScript("TimelinePresentationModel.js");
Modified: trunk/Source/WebCore/inspector/front-end/WebKit.qrc (142625 => 142626)
--- trunk/Source/WebCore/inspector/front-end/WebKit.qrc 2013-02-12 15:53:48 UTC (rev 142625)
+++ trunk/Source/WebCore/inspector/front-end/WebKit.qrc 2013-02-12 15:56:28 UTC (rev 142626)
@@ -114,6 +114,7 @@
<file>MetricsSidebarPane.js</file>
<file>NativeBreakpointsSidebarPane.js</file>
<file>NativeHeapSnapshot.js</file>
+ <file>NativeMemoryGraph.js</file>
<file>NativeMemorySnapshotView.js</file>
<file>NavigatorOverlayController.js</file>
<file>NavigatorView.js</file>
Modified: trunk/Source/WebCore/inspector/front-end/timelinePanel.css (142625 => 142626)
--- trunk/Source/WebCore/inspector/front-end/timelinePanel.css 2013-02-12 15:53:48 UTC (rev 142625)
+++ trunk/Source/WebCore/inspector/front-end/timelinePanel.css 2013-02-12 15:56:28 UTC (rev 142626)
@@ -543,7 +543,7 @@
border-right: 1px solid #AAA;
}
-#memory-graphs-canvas-container .resources-dividers {
+#memory-graphs-canvas-container.dom-counters .resources-dividers {
top: 15px;
}
@@ -684,3 +684,7 @@
.image-container {
padding: 0;
}
+
+.memory-category-value {
+ float: right;
+}