mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-10 02:08:38 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
33
layout/forms/crashtests/1102791.html
Normal file
33
layout/forms/crashtests/1102791.html
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html class="reftest-print"><head>
|
||||
<meta charset="utf-8">
|
||||
<title>Testcase for bug 1102791</title>
|
||||
<style type="text/css">
|
||||
|
||||
html,body {
|
||||
color:black; background-color:white; font-size:16px; padding:0; margin:0;
|
||||
}
|
||||
|
||||
button {
|
||||
position: absolute;
|
||||
-moz-appearance: none;
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
border-style:none;
|
||||
}
|
||||
button::before {
|
||||
position: absolute;
|
||||
content: "::before";
|
||||
width: 10px;
|
||||
height: 200em;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<button></button>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
20
layout/forms/crashtests/1140216.html
Normal file
20
layout/forms/crashtests/1140216.html
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
|
||||
input { -moz-appearance: textfield; }
|
||||
|
||||
</style>
|
||||
<script>
|
||||
|
||||
function boom()
|
||||
{
|
||||
window.getComputedStyle(x, "::-moz-number-spin-down").getPropertyValue("color");
|
||||
}
|
||||
|
||||
</script>
|
||||
<body onload="boom();">
|
||||
<input type="number" id="x">
|
||||
</body>
|
||||
</html>
|
||||
17
layout/forms/crashtests/1182414.html
Normal file
17
layout/forms/crashtests/1182414.html
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="reftest-print">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style type="text/css">
|
||||
#menu { position: fixed; left: 0px; top: 0px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<svg id="canvas" width="2427" height="2295.5" version="1.1" xmlns="http://www.w3.org/2000/svg"></svg>
|
||||
|
||||
<div id="menu">
|
||||
<input id="chooseSize" type="range">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
27
layout/forms/crashtests/1212688.html
Normal file
27
layout/forms/crashtests/1212688.html
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<style type="text/css">
|
||||
optgroup {overflow-x: hidden;}
|
||||
</style>
|
||||
<select>
|
||||
<optgroup label="optgroup">
|
||||
<option>1</option>
|
||||
<option>2</option>
|
||||
<option>3</option>
|
||||
<option>4</option>
|
||||
<option>5</option>
|
||||
<option>6</option>
|
||||
<option>7</option>
|
||||
<option>8</option>
|
||||
<option>9</option>
|
||||
<option>10</option>
|
||||
<option>11</option>
|
||||
<option>12</option>
|
||||
<option>13</option>
|
||||
<option>14</option>
|
||||
<option>15</option>
|
||||
<option>16</option>
|
||||
<option>17</option>
|
||||
<option>18</option>
|
||||
<option>19</option>
|
||||
<option>20</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
7
layout/forms/crashtests/1228670.xhtml
Normal file
7
layout/forms/crashtests/1228670.xhtml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<body>
|
||||
<select>
|
||||
<optgroup style="display: list-item; list-style: inside;"></optgroup>
|
||||
</select>
|
||||
</body>
|
||||
</html>
|
||||
21
layout/forms/crashtests/1279354.html
Normal file
21
layout/forms/crashtests/1279354.html
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html class="reftest-print"><head>
|
||||
<meta charset="utf-8">
|
||||
<title>Testcase for bug 1279354</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div style="position:fixed"><progress></progress></div>
|
||||
1
|
||||
<br style="page-break-after: always">
|
||||
2
|
||||
<br style="page-break-after: always">
|
||||
3
|
||||
<br style="page-break-after: always">
|
||||
|
||||
</body>
|
||||
</html>
|
||||
14
layout/forms/crashtests/166750-1.html
Normal file
14
layout/forms/crashtests/166750-1.html
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head><title>Killer</title></head>
|
||||
<body>
|
||||
<form style="overflow: auto;">
|
||||
<select style="position: fixed;">
|
||||
<option>First</option>
|
||||
<option>Second</option>
|
||||
<option>Third</option>
|
||||
</select>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
8
layout/forms/crashtests/200347-1.html
Normal file
8
layout/forms/crashtests/200347-1.html
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<body>
|
||||
<fieldset style="width: 300px; position: fixed">
|
||||
<legend>Crash test</legend>
|
||||
<div style="float: right; background-color: orange; border: 1px solid black">Hello, my name is Inigo Montoya.</div> hello world content is the best content around, I love hello world content to death, especially when it wraps; that just gives me the chills. Anything less than hello world content is uncivilized.
|
||||
</fieldset>
|
||||
</body>
|
||||
</html>
|
||||
24
layout/forms/crashtests/203041-1.html
Normal file
24
layout/forms/crashtests/203041-1.html
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<html>
|
||||
|
||||
<head></head>
|
||||
|
||||
<body>
|
||||
<form method="post" action="#" enctype="multipart/form-data" name="content">
|
||||
|
||||
<div id="sshot" style="position:absolute; left:0; top:70; width:600;
|
||||
visibility:visible">
|
||||
<input type="file" name="sshot-1" size="20">
|
||||
</div>
|
||||
|
||||
<div id="comment" style="position:absolute; left:0; top:70; width:600;
|
||||
visibility:hidden"></div>
|
||||
|
||||
<script language="JavaScript">
|
||||
<!--
|
||||
document.documentElement.offsetHeight;
|
||||
document.getElementById('sshot').style.display = 'none';
|
||||
document.getElementById('comment').style.display = 'none';
|
||||
// -->
|
||||
</script>
|
||||
</form>
|
||||
</body></html>
|
||||
23
layout/forms/crashtests/213390-1.html
Normal file
23
layout/forms/crashtests/213390-1.html
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd">
|
||||
|
||||
<HTML>
|
||||
<BODY>
|
||||
|
||||
<EMBED>
|
||||
|
||||
<TABLE>
|
||||
<TR>
|
||||
<TD STYLE="FONT: 10px Arial;">
|
||||
<A STYLE="FONT: 11px Arial;">1</A>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
<DIV STYLE="POSITION: absolute;">
|
||||
<FORM>
|
||||
<SELECT STYLE="FONT: 11px Arial;">
|
||||
</FORM>
|
||||
</DIV>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
18
layout/forms/crashtests/258101-1.html
Normal file
18
layout/forms/crashtests/258101-1.html
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta content="text/html; charset=ISO-8859-1"
|
||||
http-equiv="content-type">
|
||||
<title>Crash Testcase</title>
|
||||
<script type="text/javascript">
|
||||
function crash()
|
||||
{
|
||||
var inp = document.getElementById("theinp");
|
||||
inp.type = "file";
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="crash();">
|
||||
<input id="theinp" type="text">
|
||||
</body>
|
||||
</html>
|
||||
7
layout/forms/crashtests/266225-1.html
Normal file
7
layout/forms/crashtests/266225-1.html
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<HTML>
|
||||
<HEAD>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<FIELDSET STYLE="float:right; text-indent:999px;">Test</FIELDSET>
|
||||
</BODY>
|
||||
</HTML>
|
||||
9
layout/forms/crashtests/310426-1.xhtml
Normal file
9
layout/forms/crashtests/310426-1.xhtml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
|
||||
<body>
|
||||
|
||||
<select><span style="position: absolute;" /></select>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
19
layout/forms/crashtests/310520-1.xhtml
Normal file
19
layout/forms/crashtests/310520-1.xhtml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
|
||||
<script><![CDATA[
|
||||
|
||||
function init()
|
||||
{
|
||||
var select = document.getElementsByTagName("select")[0];
|
||||
select.parentNode.removeChild(select);
|
||||
}
|
||||
|
||||
window.addEventListener("load", init, 0);
|
||||
|
||||
]]></script>
|
||||
|
||||
|
||||
</head>
|
||||
<body><select><input/></select></body>
|
||||
</html>
|
||||
21
layout/forms/crashtests/315752-1.xhtml
Normal file
21
layout/forms/crashtests/315752-1.xhtml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:xml="http://www.w3.org/XML/1998/namespace">
|
||||
<head>
|
||||
<title>Settings - Unclassified NewsBoard</title>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<select name="Language">
|
||||
<option value="" style="clear: right;">
|
||||
Automatic </option>
|
||||
<option value="de" style="clear: right;">
|
||||
<span alt="" style="float: right; margin-top: 1px;"> Deutsch</span> <small>(de)</small> </option>
|
||||
<option value="en" selected="selected" style="clear: right;">
|
||||
<span alt="" style="float: right; margin-top: 1px;"> English</span> <small>(en)</small> </option>
|
||||
</select>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
13
layout/forms/crashtests/317502-1.xhtml
Normal file
13
layout/forms/crashtests/317502-1.xhtml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
|
||||
<head>
|
||||
<title>Testcase, bug 317502</title>
|
||||
</head>
|
||||
<body onload="document.getElementsByTagName('input')[0].style.width='200px'">
|
||||
|
||||
<input type="file" style="position: fixed" />
|
||||
|
||||
</body>
|
||||
</html>
|
||||
17
layout/forms/crashtests/321894.html
Normal file
17
layout/forms/crashtests/321894.html
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<html><head>
|
||||
<title>
|
||||
Testcase bug 321894 - ASSERTION: RemovedAsPrimaryFrame called after PreDestroy: 'PR_FALSE'
|
||||
</title>
|
||||
</head>
|
||||
<body>
|
||||
This shouldn't assert in a debug build
|
||||
<span>
|
||||
<script>var x=document.body.offsetHeight;</script>
|
||||
<div>
|
||||
<span style="float:left;">
|
||||
<input type="text">
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
</body>
|
||||
</html>
|
||||
21
layout/forms/crashtests/323499-1.html
Normal file
21
layout/forms/crashtests/323499-1.html
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<html>
|
||||
<head>
|
||||
|
||||
<style>
|
||||
select {
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
body {
|
||||
display: -moz-grid-group;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<select><option>a</option></select>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
4
layout/forms/crashtests/343510-1.html
Normal file
4
layout/forms/crashtests/343510-1.html
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<select style="position: absolute;">
|
||||
<meta>
|
||||
<option style="position: absolute;">
|
||||
<body style="display: block;">
|
||||
10
layout/forms/crashtests/363696-1.xul
Normal file
10
layout/forms/crashtests/363696-1.xul
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<body>
|
||||
|
||||
<xul:hbox>
|
||||
<input type="file" />
|
||||
</xul:hbox>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
2
layout/forms/crashtests/363696-2.html
Normal file
2
layout/forms/crashtests/363696-2.html
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
<div style="display: -moz-grid-line;">
|
||||
<input type="file">
|
||||
5
layout/forms/crashtests/363696-3.html
Normal file
5
layout/forms/crashtests/363696-3.html
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<html><head></head><body>
|
||||
|
||||
<span style="display: -moz-box;"><input type="file"><textarea></textarea></span>
|
||||
|
||||
</body></html>
|
||||
11
layout/forms/crashtests/366205-1.html
Normal file
11
layout/forms/crashtests/366205-1.html
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body onload='var yar=document.getElementById("yar"); yar.parentNode.removeChild(yar); document.getElementById("foo").removeAttribute("multiple");'>
|
||||
|
||||
<div id="yar">Clicking the button below should not trigger an assertion</div>
|
||||
|
||||
<select id="foo" multiple><option>A</option></select>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
32
layout/forms/crashtests/366537-1.xhtml
Normal file
32
layout/forms/crashtests/366537-1.xhtml
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-wait">
|
||||
|
||||
<head>
|
||||
<script>
|
||||
|
||||
function boom()
|
||||
{
|
||||
var fieldset = document.getElementById("fieldset");
|
||||
var h3 = document.getElementById("h3");
|
||||
var legend = document.getElementById("legend");
|
||||
|
||||
fieldset.appendChild(legend);
|
||||
fieldset.appendChild(h3);
|
||||
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
|
||||
<body onload="setTimeout(boom, 30);">
|
||||
|
||||
<legend id="legend">legend</legend>
|
||||
|
||||
<h3 id="h3">H3</h3>
|
||||
|
||||
<select><option>option<fieldset id="fieldset"></fieldset></option></select>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
37
layout/forms/crashtests/367587-1.html
Normal file
37
layout/forms/crashtests/367587-1.html
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<html class="reftest-wait">
|
||||
<head>
|
||||
|
||||
<style>
|
||||
|
||||
#opt1 { display: table-footer-group; }
|
||||
#opt1 { visibility: collapse; }
|
||||
#opt1 { overflow: -moz-scrollbars-vertical; }
|
||||
|
||||
#opt2 { display: table-cell; }
|
||||
#opt2 { clear: left; }
|
||||
|
||||
select { width: 1px; }
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
function boom()
|
||||
{
|
||||
document.getElementById("opt2").style.clear = "none";
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="setTimeout(boom, 30);">
|
||||
|
||||
<select multiple>
|
||||
<option id="opt1">A</option>
|
||||
<option id="opt2">B</option>
|
||||
</select>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
30
layout/forms/crashtests/370703-1.html
Normal file
30
layout/forms/crashtests/370703-1.html
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<html class="reftest-wait">
|
||||
<head>
|
||||
<script>
|
||||
|
||||
function boom()
|
||||
{
|
||||
document.getElementById("M").style.width = "6em";
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<body onload="setTimeout(boom, 30);">
|
||||
|
||||
<div style="position:absolute; top: 50px; left: 50px; border: 2px solid orange;">
|
||||
|
||||
<select>
|
||||
<option id="M">M</option>
|
||||
</select>
|
||||
|
||||
<br>
|
||||
|
||||
<select style="width: 200%">
|
||||
<option style="visibility: collapse; overflow: auto; display: table-footer-group;">X</option>
|
||||
</select>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
28
layout/forms/crashtests/370940-1.html
Normal file
28
layout/forms/crashtests/370940-1.html
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<html class="reftest-wait">
|
||||
<head>
|
||||
<script>
|
||||
|
||||
var HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
|
||||
function boom1()
|
||||
{
|
||||
var newSpan = document.createElementNS(HTML_NS, "span");
|
||||
document.body.appendChild(newSpan);
|
||||
|
||||
setTimeout(boom2, 30);
|
||||
}
|
||||
|
||||
function boom2()
|
||||
{
|
||||
var newDiv = document.createElementNS(HTML_NS, "div");
|
||||
document.getElementById("s").appendChild(newDiv);
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="setTimeout(boom1, 30);">
|
||||
<p>العربي</p>
|
||||
<span id="s"></span><input><select></select><isindex><span></span>
|
||||
</body>
|
||||
</html>
|
||||
13
layout/forms/crashtests/370967.html
Normal file
13
layout/forms/crashtests/370967.html
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Untitled</title>
|
||||
</head>
|
||||
<body>
|
||||
Focus the input of the isindex, then do a reload, Mozilla should not crash
|
||||
<isindex autofocus>
|
||||
</label>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
40
layout/forms/crashtests/373586-1.xhtml
Normal file
40
layout/forms/crashtests/373586-1.xhtml
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-wait">
|
||||
<head>
|
||||
|
||||
<bindings xmlns="http://www.mozilla.org/xbl">
|
||||
<binding id="foo">
|
||||
<content>
|
||||
<children xmlns="http://www.mozilla.org/xbl" />
|
||||
</content>
|
||||
</binding>
|
||||
</bindings>
|
||||
|
||||
<script>
|
||||
function boom()
|
||||
{
|
||||
document.getElementById("div").style.MozBinding = "url('#foo')";
|
||||
|
||||
var opt1 = document.getElementById("opt1");
|
||||
opt1.removeChild(opt1.firstChild);
|
||||
|
||||
document.getElementById("textarea").value += " ";
|
||||
|
||||
document.documentElement.removeAttribute("class")
|
||||
}
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="setTimeout(boom, 30);">
|
||||
|
||||
<div id="div">
|
||||
<textarea rows="3" cols="5" id="textarea"></textarea>
|
||||
</div>
|
||||
|
||||
<select>
|
||||
<option id="opt1">opt1</option>
|
||||
</select>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
4
layout/forms/crashtests/375299-binding.xml
Normal file
4
layout/forms/crashtests/375299-binding.xml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<bindings xmlns="http://www.mozilla.org/xbl">
|
||||
<binding id="a">
|
||||
<content><children/></content>
|
||||
</binding></bindings>
|
||||
17
layout/forms/crashtests/375299.html
Normal file
17
layout/forms/crashtests/375299.html
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<html><head>
|
||||
<title>Testcase bug - Crash [@ nsFileControlFrame::CreateAnonymousContent] when removing stylesheet with binding and removing file input</title>
|
||||
<style>
|
||||
body {-moz-binding:url("375299-binding.xml#a"); }
|
||||
</style>
|
||||
</head><body onload="doe()">
|
||||
<input type="file">
|
||||
|
||||
<script>
|
||||
function doe() {
|
||||
var x=document.getElementsByTagName('input')[0];
|
||||
x.parentNode.removeChild(x);
|
||||
var y=document.getElementsByTagName('style')[0];
|
||||
y.parentNode.removeChild(y);
|
||||
}
|
||||
</script>
|
||||
</body></html>
|
||||
19
layout/forms/crashtests/378369.html
Normal file
19
layout/forms/crashtests/378369.html
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Testcase bug - Crash [@ nsEventListenerManager::FixContextMenuEvent] when firing contextmenu event in display: none iframe</title>
|
||||
</head>
|
||||
<body>
|
||||
This page should not crash Mozilla
|
||||
<iframe style="display: none;"></iframe>
|
||||
|
||||
<script>
|
||||
function docontextmenu(i){
|
||||
var doc = window.frames[0].document;
|
||||
var ev = doc.createEvent ('MouseEvents');
|
||||
ev.initMouseEvent('contextmenu', true,true, window, 3,5, 5, 400, 400, 0, 0, 0,0,0,null);
|
||||
doc.dispatchEvent(ev);
|
||||
}
|
||||
setTimeout(docontextmenu,0);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
16
layout/forms/crashtests/378413-1.xhtml
Normal file
16
layout/forms/crashtests/378413-1.xhtml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<body style="direction: rtl;">
|
||||
|
||||
<form style="display: -moz-deck; width: 1em;">
|
||||
<fieldset>
|
||||
<legend>Your name</legend>
|
||||
<input type="text" name="name" size="20"/>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Your E-mail address</legend>
|
||||
<input type="text" name="email" size="25"/>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
11
layout/forms/crashtests/380116-1.xhtml
Normal file
11
layout/forms/crashtests/380116-1.xhtml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<body onload="document.getElementById('t').style.display = 'block';">
|
||||
|
||||
<table border="1" id="t">
|
||||
<tr>
|
||||
<td><select><option>foopy</option></select></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
7
layout/forms/crashtests/382212-1.xhtml
Normal file
7
layout/forms/crashtests/382212-1.xhtml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<body>
|
||||
<div>
|
||||
<xul:textbox><select><option>foo</option></select></xul:textbox>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
11
layout/forms/crashtests/382610-1.html
Normal file
11
layout/forms/crashtests/382610-1.html
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<div style="position: absolute">
|
||||
<input type="file" style="position: absolute; -moz-appearance: menulist;">
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
20
layout/forms/crashtests/383887-1.html
Normal file
20
layout/forms/crashtests/383887-1.html
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<select>
|
||||
<option style="padding: 200%;">
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div style="padding: 200%"><span style="float: left; border: 1px solid red;"></span></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
14
layout/forms/crashtests/386554-1.html
Normal file
14
layout/forms/crashtests/386554-1.html
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<html>
|
||||
<head></head>
|
||||
|
||||
<body>
|
||||
|
||||
<div style="position: absolute"><input id="input" type="file" style="top: 100%"></div>
|
||||
|
||||
<script>
|
||||
document.body.offsetHeight;
|
||||
document.getElementById("input").style.position = "absolute";
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
22
layout/forms/crashtests/388374-1.xhtml
Normal file
22
layout/forms/crashtests/388374-1.xhtml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<script>
|
||||
function boom()
|
||||
{
|
||||
var newText = document.createTextNode('x');
|
||||
document.getElementById("a").parentNode.appendChild(newText);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="boom()">
|
||||
|
||||
<table border="1">
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td id="a" style="padding-left: 10%"><select style="padding-left: 20%; bottom: 10%;"><option style="padding: 0 0 10% 20%;">pppp</option></select></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
25
layout/forms/crashtests/388374-2.html
Normal file
25
layout/forms/crashtests/388374-2.html
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<script>
|
||||
function boom()
|
||||
{
|
||||
var newDiv = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
|
||||
newDiv.style.width = "100px";
|
||||
newDiv.style.height = "8px";
|
||||
newDiv.style.background = "lightgreen";
|
||||
document.getElementById("tr").appendChild(newDiv);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="boom()">
|
||||
|
||||
<table border="1">
|
||||
<tr id="tr">
|
||||
<td></td>
|
||||
<td style="padding-left: 10%"><select style="padding-left: 20%; bottom: 10%;"><option style="padding: 0 0 10% 20%; width: 25px;"></option></select></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
13
layout/forms/crashtests/393656-1.xhtml
Normal file
13
layout/forms/crashtests/393656-1.xhtml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<select style="float: right; clear: right;">
|
||||
<option><a style="float: right;"></a></option>
|
||||
<option style="margin: 100%;"></option>
|
||||
<option><div style="clear: both"></div></option>
|
||||
</select>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
22
layout/forms/crashtests/393656-2.xhtml
Normal file
22
layout/forms/crashtests/393656-2.xhtml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="overflow: hidden;">
|
||||
<div style="float: right;"><span>XXX</span></div>
|
||||
<select style="float: right; clear: right;">
|
||||
<option><a style="float: right;"></a></option>
|
||||
<option style="margin: 100%;"></option>
|
||||
<option><div style="clear: both"></div></option>
|
||||
</select>
|
||||
<dl style="float: left;"></dl>
|
||||
<div>
|
||||
<div style="float: left;"></div>
|
||||
<div style="display: block; clear: both"></div>
|
||||
<dl style="float: left;"></dl>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
50
layout/forms/crashtests/399262.html
Normal file
50
layout/forms/crashtests/399262.html
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<style>
|
||||
select::first-letter, option::first-letter { color:green; }
|
||||
.block select, .block option{ display:block; }
|
||||
.scroll select, .scroll option{ display:block; overflow:hidden; }
|
||||
</style>
|
||||
|
||||
<select></select>
|
||||
<select>F</select>
|
||||
<select>Ff</select>
|
||||
<select><option>F</select>
|
||||
<select><option>Ff</select>
|
||||
|
||||
<div class="block">
|
||||
<select></select>
|
||||
<select>F</select>
|
||||
<select>Ff</select>
|
||||
<select><option>F</select>
|
||||
<select><option>Ff</select>
|
||||
</div>
|
||||
|
||||
<div class="scroll">
|
||||
<select></select>
|
||||
<select>F</select>
|
||||
<select>Ff</select>
|
||||
<select><option>F</select>
|
||||
<select><option>Ff</select>
|
||||
</div>
|
||||
|
||||
<select size=2></select>
|
||||
<select size=2>F</select>
|
||||
<select size=2>Ff</select>
|
||||
<select size=2><option>F</select>
|
||||
<select size=2><option>Ff</select>
|
||||
|
||||
<div class="block">
|
||||
<select size=2></select>
|
||||
<select size=2>F</select>
|
||||
<select size=2>Ff</select>
|
||||
<select size=2><option>F</select>
|
||||
<select size=2><option>Ff</select>
|
||||
</div>
|
||||
|
||||
<div class="scroll">
|
||||
<select size=2></select>
|
||||
<select size=2>F</select>
|
||||
<select size=2>Ff</select>
|
||||
<select size=2><option>F</select>
|
||||
<select size=2><option>Ff</select>
|
||||
</div>
|
||||
|
||||
2
layout/forms/crashtests/402852-1.html
Normal file
2
layout/forms/crashtests/402852-1.html
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
<body style="text-indent: 99999999999999999999px;">
|
||||
<fieldset>
|
||||
22
layout/forms/crashtests/403148-1.html
Normal file
22
layout/forms/crashtests/403148-1.html
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<html>
|
||||
<head>
|
||||
<script>
|
||||
|
||||
function boom()
|
||||
{
|
||||
document.getElementById("ce").contentEditable = true;
|
||||
document.documentElement.offsetHeight;
|
||||
document.getElementById("finput").setAttribute("type", "");
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="boom();">
|
||||
|
||||
<input id="finput" type="file" disabled>
|
||||
|
||||
<span id="ce"></span>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
5
layout/forms/crashtests/404118-1.html
Normal file
5
layout/forms/crashtests/404118-1.html
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<html>
|
||||
<body>
|
||||
<input type="file" style="position: fixed; height: 0; width: 10px; white-space: normal;">
|
||||
</body>
|
||||
</html>
|
||||
12
layout/forms/crashtests/404123-1.html
Normal file
12
layout/forms/crashtests/404123-1.html
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<fieldset>
|
||||
<legend style="padding: 0pt 100%;"></legend>
|
||||
</fieldset>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
1
layout/forms/crashtests/407066.html
Normal file
1
layout/forms/crashtests/407066.html
Normal file
|
|
@ -0,0 +1 @@
|
|||
<div style="display: inline-block; -moz-column-count: 2;">text<input type="reset" style="float: right;">
|
||||
7
layout/forms/crashtests/451316.html
Normal file
7
layout/forms/crashtests/451316.html
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<div style="-moz-column-width: 1px;"><select style="height: 12em; display: block;"></select></div>
|
||||
<div style="-moz-column-width: 1px;"><select multiple style="height: 12em; display: block;"></select></div>
|
||||
</body>
|
||||
</html>
|
||||
17
layout/forms/crashtests/455451-1.html
Normal file
17
layout/forms/crashtests/455451-1.html
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
|
||||
function boom()
|
||||
{
|
||||
window.addEventListener("DOMCharacterDataModified", function(){}, false);
|
||||
document.body.appendChild(document.createElement("isindex"));
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="boom();"></body>
|
||||
|
||||
</html>
|
||||
17
layout/forms/crashtests/457537-1.html
Normal file
17
layout/forms/crashtests/457537-1.html
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
|
||||
function boom()
|
||||
{
|
||||
window.addEventListener("DOMAttrModified", function(){}, false);
|
||||
document.body.appendChild(document.createElement("input"));
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="boom();"></body>
|
||||
|
||||
</html>
|
||||
17
layout/forms/crashtests/457537-2.html
Normal file
17
layout/forms/crashtests/457537-2.html
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
|
||||
function boom()
|
||||
{
|
||||
window.addEventListener("DOMAttrModified", function(){}, false);
|
||||
document.body.appendChild(document.createElement("isindex"));
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="boom();"></body>
|
||||
|
||||
</html>
|
||||
7
layout/forms/crashtests/478219-1.xhtml
Normal file
7
layout/forms/crashtests/478219-1.xhtml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:mathml="http://www.w3.org/1998/Math/MathML" xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<div>
|
||||
<xul:textbox onDOMAttrModified="this.parentNode.removeChild(this)">
|
||||
<mathml:mathml/>
|
||||
</xul:textbox>
|
||||
</div>
|
||||
</html>
|
||||
6
layout/forms/crashtests/498698-1.html
Normal file
6
layout/forms/crashtests/498698-1.html
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<select style="height: 3401091640591pc"></select>
|
||||
</body>
|
||||
</html>
|
||||
6
layout/forms/crashtests/513113-1.html
Normal file
6
layout/forms/crashtests/513113-1.html
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<html><body onload="document.body.style.display = 'table';" style="-moz-column-count: 1; white-space: pre-line; -moz-appearance: resizer; height: 23698324514pc;">
|
||||
|
||||
|
||||
|
||||
<input></body></html>
|
||||
20
layout/forms/crashtests/538062-1.xhtml
Normal file
20
layout/forms/crashtests/538062-1.xhtml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
<![CDATA[
|
||||
|
||||
function boom()
|
||||
{
|
||||
var option = document.getElementsByTagName("option")[0];
|
||||
var b = option.firstChild;
|
||||
option.appendChild(document.createTextNode("\u064A"));
|
||||
document.documentElement.offsetHeight;
|
||||
option.removeChild(b);
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="boom();"><select><option>B </option></select></body>
|
||||
</html>
|
||||
15
layout/forms/crashtests/570624-1.html
Normal file
15
layout/forms/crashtests/570624-1.html
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<script>
|
||||
function boom()
|
||||
{
|
||||
var xt = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", 'textbox');
|
||||
document.body.appendChild(xt);
|
||||
xt.setAttribute('disabled', "true");
|
||||
xt.setAttribute('value', "foo");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="boom();">
|
||||
</body>
|
||||
</html>
|
||||
17
layout/forms/crashtests/578604-1.html
Normal file
17
layout/forms/crashtests/578604-1.html
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<html class="reftest-print">
|
||||
<head>
|
||||
<style>
|
||||
h2 { page-break-before: always; }
|
||||
#reviewer { position: fixed;}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h2>Crash Test Case</h2>
|
||||
<div>
|
||||
<input id='reviewer'>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
4
layout/forms/crashtests/590302-1.xhtml
Normal file
4
layout/forms/crashtests/590302-1.xhtml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<html class="reftest-print" xmlns="http://www.w3.org/1999/xhtml" style=" float: left; white-space: pre; ">
|
||||
<div style="page-break-before: always;"></div>
|
||||
<textarea style="position: fixed;"></textarea>
|
||||
</html>
|
||||
20
layout/forms/crashtests/626014.xhtml
Normal file
20
layout/forms/crashtests/626014.xhtml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<script>
|
||||
<![CDATA[
|
||||
|
||||
function boom()
|
||||
{
|
||||
document.getElementById("i").selectionEnd;
|
||||
document.getElementById("a").appendChild(document.getElementById("b"));
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
</head>
|
||||
<body onload="boom();">
|
||||
|
||||
<mrow xmlns="http://www.w3.org/1998/Math/MathML" id="a"><mrow id="b"/><input xmlns="http://www.w3.org/1999/xhtml" id="i" /></mrow>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
26
layout/forms/crashtests/639733.xhtml
Normal file
26
layout/forms/crashtests/639733.xhtml
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<script>
|
||||
<![CDATA[
|
||||
|
||||
function remove(n)
|
||||
{
|
||||
n.parentNode.removeChild(n);
|
||||
}
|
||||
|
||||
function boom()
|
||||
{
|
||||
|
||||
document.documentElement.offsetHeight;
|
||||
remove(document.getElementById("s"));
|
||||
remove(document.getElementById("e"));
|
||||
document.documentElement.offsetHeight;
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
</head>
|
||||
<body onload="boom();">
|
||||
<embed id="e" src="data:text/html,A"></embed><span id="s"><div></div></span><isindex/>
|
||||
</body>
|
||||
</html>
|
||||
14
layout/forms/crashtests/669767.html
Normal file
14
layout/forms/crashtests/669767.html
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Untitled</title>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="data:text/html;charset=utf-8,%3Chtml%3E%3Chead%3E%3C/head%3E%3Cbody%3E%0A%3Ctextarea%3E%3C/textarea%3E%0A%0A%0A%3Cstyle%3E%0A@font-face%20%7B%0A%20%20%20%20%20%20font-family%3A%20%22cutabovetherest%22%3B%0A%20%20%20%20%20%20src%3A%20url%28%22http%3A//www.webpagepublicity.com/free-fonts/a/A%2520Cut%2520Above%2520The%2520Rest.ttf%22%29%3B%0A%7D%20%20%20%20%0A%0A%3C/style%3E%0A%0A%3Coptgroup%20contenteditable%3D%22true%22%20style%3D%22display%3A%20inline%3B%22%3E%3C/optgroup%3E%0A%0A%3C/body%3E%3C/html%3E"></iframe>
|
||||
<script>
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
4
layout/forms/crashtests/682684-binding.xml
Normal file
4
layout/forms/crashtests/682684-binding.xml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<style>html::before { content:"b"; }</style>
|
||||
<input contenteditable="true" spellcheck="true"/>
|
||||
</html>
|
||||
3
layout/forms/crashtests/682684.xhtml
Normal file
3
layout/forms/crashtests/682684.xhtml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<span style="mask: url(682684-binding.xml#a);"/>
|
||||
</html>
|
||||
9
layout/forms/crashtests/865602.html
Normal file
9
layout/forms/crashtests/865602.html
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html><body>
|
||||
|
||||
<div style="-moz-column-count: 2;"><fieldset style="transform-style: preserve-3d;"><fieldset style="white-space: pre-line; position: fixed;"><div style="position: fixed;">
|
||||
|
||||
|
||||
</div></fieldset></fieldset></div>
|
||||
|
||||
</body></html>
|
||||
10
layout/forms/crashtests/893332-1.html
Normal file
10
layout/forms/crashtests/893332-1.html
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
</head>
|
||||
<body>
|
||||
<input min="-10" max="10" step="0.1" type="range" value="-5"/>
|
||||
<input max="50" min="10" step="2" type="range" value="7"/>
|
||||
</body>
|
||||
</html>
|
||||
9
layout/forms/crashtests/944198.html
Normal file
9
layout/forms/crashtests/944198.html
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
</head>
|
||||
<body onload="c.removeAttribute('type'); c.removeAttribute('value');">
|
||||
<input id="c" type="color">
|
||||
</body>
|
||||
</html>
|
||||
5
layout/forms/crashtests/949891.xhtml
Normal file
5
layout/forms/crashtests/949891.xhtml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<body>
|
||||
<input type="number"> </input>
|
||||
</body>
|
||||
</html>
|
||||
17
layout/forms/crashtests/959311.html
Normal file
17
layout/forms/crashtests/959311.html
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="reftest-print">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style type="text/css">
|
||||
@page { size:5in 3in; margin:0in; }
|
||||
div { height: 2.5in; }
|
||||
select { height: 0.5in; display:block; padding:20px; page-break-inside:initial; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div></div>
|
||||
<select>
|
||||
<option>Text</option>
|
||||
</select>
|
||||
</body>
|
||||
</html>
|
||||
14
layout/forms/crashtests/960277-2.html
Normal file
14
layout/forms/crashtests/960277-2.html
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE HTML>
|
||||
<style>
|
||||
#d { overflow:scroll; width:200px; height:200px; background:yellow; }
|
||||
#d2 { right:0; width:100px; height:100px; background:purple; }
|
||||
</style>
|
||||
<fieldset id="d">
|
||||
<div id="d2"></div>
|
||||
</fieldset>
|
||||
<script>
|
||||
d.getBoundingClientRect();
|
||||
d.style.transform = "translateX(100px)";
|
||||
d.getBoundingClientRect();
|
||||
d2.style.position = "absolute";
|
||||
</script>
|
||||
5
layout/forms/crashtests/997709-1.html
Normal file
5
layout/forms/crashtests/997709-1.html
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html class="reftest-print"><body><div style="position: fixed;">
|
||||
<div style="page-break-after: always"></div>
|
||||
<select style="display:flex; position: fixed;"><option>A</select>
|
||||
</div></body></html>
|
||||
69
layout/forms/crashtests/crashtests.list
Normal file
69
layout/forms/crashtests/crashtests.list
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
load 166750-1.html
|
||||
load 200347-1.html
|
||||
load 203041-1.html
|
||||
load 213390-1.html
|
||||
load 258101-1.html
|
||||
load 266225-1.html
|
||||
load 310426-1.xhtml
|
||||
load 310520-1.xhtml
|
||||
load 315752-1.xhtml
|
||||
load 317502-1.xhtml
|
||||
load 321894.html
|
||||
load 323499-1.html
|
||||
load 343510-1.html
|
||||
load 363696-1.xul
|
||||
load 363696-2.html
|
||||
load 363696-3.html
|
||||
load 366205-1.html
|
||||
load 366537-1.xhtml
|
||||
load 367587-1.html
|
||||
load 370703-1.html
|
||||
load 370940-1.html
|
||||
load 370967.html
|
||||
load 373586-1.xhtml
|
||||
load 375299.html
|
||||
load 378369.html
|
||||
asserts(4-10) load 378413-1.xhtml # bug 424225, bug 402850?
|
||||
load 380116-1.xhtml
|
||||
load 382212-1.xhtml
|
||||
load 382610-1.html
|
||||
load 383887-1.html
|
||||
load 386554-1.html
|
||||
load 388374-1.xhtml
|
||||
load 388374-2.html
|
||||
load 393656-1.xhtml
|
||||
load 393656-2.xhtml
|
||||
load 399262.html
|
||||
load 402852-1.html
|
||||
load 403148-1.html
|
||||
load 404118-1.html
|
||||
load 404123-1.html
|
||||
load 407066.html
|
||||
load 451316.html
|
||||
load 455451-1.html
|
||||
load 457537-1.html
|
||||
load 457537-2.html
|
||||
load 478219-1.xhtml
|
||||
load 498698-1.html
|
||||
load 513113-1.html
|
||||
load 538062-1.xhtml
|
||||
load 570624-1.html
|
||||
asserts(1) load 578604-1.html # bug 584564
|
||||
asserts(4-7) load 590302-1.xhtml # bug 584564
|
||||
load 626014.xhtml
|
||||
load 639733.xhtml
|
||||
load 669767.html
|
||||
load 682684.xhtml
|
||||
load 865602.html
|
||||
load 893332-1.html
|
||||
load 944198.html
|
||||
load 949891.xhtml
|
||||
load 959311.html
|
||||
load 960277-2.html
|
||||
load 997709-1.html
|
||||
load 1102791.html
|
||||
load 1140216.html
|
||||
load 1182414.html
|
||||
load 1212688.html
|
||||
load 1228670.xhtml
|
||||
load 1279354.html
|
||||
57
layout/forms/moz.build
Normal file
57
layout/forms/moz.build
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('Core', 'Layout: Form Controls')
|
||||
|
||||
MOCHITEST_MANIFESTS += ['test/mochitest.ini']
|
||||
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
|
||||
|
||||
EXPORTS += [
|
||||
'nsIComboboxControlFrame.h',
|
||||
'nsIFormControlFrame.h',
|
||||
'nsIListControlFrame.h',
|
||||
'nsISelectControlFrame.h',
|
||||
'nsITextControlFrame.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'nsButtonFrameRenderer.cpp',
|
||||
'nsColorControlFrame.cpp',
|
||||
'nsComboboxControlFrame.cpp',
|
||||
'nsDateTimeControlFrame.cpp',
|
||||
'nsFieldSetFrame.cpp',
|
||||
'nsFileControlFrame.cpp',
|
||||
'nsFormControlFrame.cpp',
|
||||
'nsGfxButtonControlFrame.cpp',
|
||||
'nsGfxCheckboxControlFrame.cpp',
|
||||
'nsGfxRadioControlFrame.cpp',
|
||||
'nsHTMLButtonControlFrame.cpp',
|
||||
'nsImageControlFrame.cpp',
|
||||
'nsLegendFrame.cpp',
|
||||
'nsListControlFrame.cpp',
|
||||
'nsMeterFrame.cpp',
|
||||
'nsNumberControlFrame.cpp',
|
||||
'nsProgressFrame.cpp',
|
||||
'nsRangeFrame.cpp',
|
||||
'nsSelectsAreaFrame.cpp',
|
||||
'nsTextControlFrame.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'../../editor/txmgr',
|
||||
'../base',
|
||||
'../generic',
|
||||
'../style',
|
||||
'../xul',
|
||||
'/dom/base',
|
||||
'/dom/html',
|
||||
]
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += ['-Wno-error=shadow']
|
||||
516
layout/forms/nsButtonFrameRenderer.cpp
Normal file
516
layout/forms/nsButtonFrameRenderer.cpp
Normal file
|
|
@ -0,0 +1,516 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "nsButtonFrameRenderer.h"
|
||||
#include "nsCSSRendering.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
#include "nsNameSpaceManager.h"
|
||||
#include "mozilla/StyleSetHandle.h"
|
||||
#include "mozilla/StyleSetHandleInlines.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "nsITheme.h"
|
||||
#include "nsFrame.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
|
||||
#define ACTIVE "active"
|
||||
#define HOVER "hover"
|
||||
#define FOCUS "focus"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::image;
|
||||
|
||||
nsButtonFrameRenderer::nsButtonFrameRenderer()
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsButtonFrameRenderer);
|
||||
}
|
||||
|
||||
nsButtonFrameRenderer::~nsButtonFrameRenderer()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsButtonFrameRenderer);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (mInnerFocusStyle) {
|
||||
mInnerFocusStyle->FrameRelease();
|
||||
}
|
||||
if (mOuterFocusStyle) {
|
||||
mOuterFocusStyle->FrameRelease();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
nsButtonFrameRenderer::SetFrame(nsFrame* aFrame, nsPresContext* aPresContext)
|
||||
{
|
||||
mFrame = aFrame;
|
||||
ReResolveStyles(aPresContext);
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsButtonFrameRenderer::GetFrame()
|
||||
{
|
||||
return mFrame;
|
||||
}
|
||||
|
||||
void
|
||||
nsButtonFrameRenderer::SetDisabled(bool aDisabled, bool notify)
|
||||
{
|
||||
if (aDisabled)
|
||||
mFrame->GetContent()->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, EmptyString(),
|
||||
notify);
|
||||
else
|
||||
mFrame->GetContent()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, notify);
|
||||
}
|
||||
|
||||
bool
|
||||
nsButtonFrameRenderer::isDisabled()
|
||||
{
|
||||
return mFrame->GetContent()->AsElement()->
|
||||
State().HasState(NS_EVENT_STATE_DISABLED);
|
||||
}
|
||||
|
||||
class nsDisplayButtonBoxShadowOuter : public nsDisplayItem {
|
||||
public:
|
||||
nsDisplayButtonBoxShadowOuter(nsDisplayListBuilder* aBuilder,
|
||||
nsButtonFrameRenderer* aRenderer)
|
||||
: nsDisplayItem(aBuilder, aRenderer->GetFrame()), mBFR(aRenderer) {
|
||||
MOZ_COUNT_CTOR(nsDisplayButtonBoxShadowOuter);
|
||||
}
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
virtual ~nsDisplayButtonBoxShadowOuter() {
|
||||
MOZ_COUNT_DTOR(nsDisplayButtonBoxShadowOuter);
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual void Paint(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext* aCtx) override;
|
||||
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
|
||||
bool* aSnap) override;
|
||||
NS_DISPLAY_DECL_NAME("ButtonBoxShadowOuter", TYPE_BUTTON_BOX_SHADOW_OUTER)
|
||||
private:
|
||||
nsButtonFrameRenderer* mBFR;
|
||||
};
|
||||
|
||||
nsRect
|
||||
nsDisplayButtonBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
|
||||
*aSnap = false;
|
||||
return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayButtonBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext* aCtx) {
|
||||
nsRect frameRect = nsRect(ToReferenceFrame(), mFrame->GetSize());
|
||||
|
||||
nsRect buttonRect;
|
||||
mBFR->GetButtonRect(frameRect, buttonRect);
|
||||
|
||||
nsCSSRendering::PaintBoxShadowOuter(mFrame->PresContext(), *aCtx, mFrame,
|
||||
buttonRect, mVisibleRect);
|
||||
}
|
||||
|
||||
class nsDisplayButtonBorder : public nsDisplayItem {
|
||||
public:
|
||||
nsDisplayButtonBorder(nsDisplayListBuilder* aBuilder,
|
||||
nsButtonFrameRenderer* aRenderer)
|
||||
: nsDisplayItem(aBuilder, aRenderer->GetFrame()), mBFR(aRenderer) {
|
||||
MOZ_COUNT_CTOR(nsDisplayButtonBorder);
|
||||
}
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
virtual ~nsDisplayButtonBorder() {
|
||||
MOZ_COUNT_DTOR(nsDisplayButtonBorder);
|
||||
}
|
||||
#endif
|
||||
virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
|
||||
HitTestState* aState,
|
||||
nsTArray<nsIFrame*> *aOutFrames) override {
|
||||
aOutFrames->AppendElement(mFrame);
|
||||
}
|
||||
virtual void Paint(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext* aCtx) override;
|
||||
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
|
||||
bool* aSnap) override;
|
||||
virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override;
|
||||
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
|
||||
const nsDisplayItemGeometry* aGeometry,
|
||||
nsRegion *aInvalidRegion) override;
|
||||
NS_DISPLAY_DECL_NAME("ButtonBorderBackground", TYPE_BUTTON_BORDER_BACKGROUND)
|
||||
private:
|
||||
nsButtonFrameRenderer* mBFR;
|
||||
};
|
||||
|
||||
nsDisplayItemGeometry*
|
||||
nsDisplayButtonBorder::AllocateGeometry(nsDisplayListBuilder* aBuilder)
|
||||
{
|
||||
return new nsDisplayItemGenericImageGeometry(this, aBuilder);
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayButtonBorder::ComputeInvalidationRegion(
|
||||
nsDisplayListBuilder* aBuilder,
|
||||
const nsDisplayItemGeometry* aGeometry,
|
||||
nsRegion *aInvalidRegion)
|
||||
{
|
||||
auto geometry =
|
||||
static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
|
||||
|
||||
if (aBuilder->ShouldSyncDecodeImages() &&
|
||||
geometry->ShouldInvalidateToSyncDecodeImages()) {
|
||||
bool snap;
|
||||
aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
|
||||
}
|
||||
|
||||
nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
|
||||
}
|
||||
|
||||
void nsDisplayButtonBorder::Paint(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext* aCtx)
|
||||
{
|
||||
NS_ASSERTION(mFrame, "No frame?");
|
||||
nsPresContext* pc = mFrame->PresContext();
|
||||
nsRect r = nsRect(ToReferenceFrame(), mFrame->GetSize());
|
||||
|
||||
// draw the border and background inside the focus and outline borders
|
||||
DrawResult result =
|
||||
mBFR->PaintBorder(aBuilder, pc, *aCtx, mVisibleRect, r);
|
||||
|
||||
nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsDisplayButtonBorder::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
|
||||
*aSnap = false;
|
||||
return aBuilder->IsForEventDelivery() ? nsRect(ToReferenceFrame(), mFrame->GetSize())
|
||||
: mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
|
||||
}
|
||||
|
||||
class nsDisplayButtonForeground : public nsDisplayItem {
|
||||
public:
|
||||
nsDisplayButtonForeground(nsDisplayListBuilder* aBuilder,
|
||||
nsButtonFrameRenderer* aRenderer)
|
||||
: nsDisplayItem(aBuilder, aRenderer->GetFrame()), mBFR(aRenderer) {
|
||||
MOZ_COUNT_CTOR(nsDisplayButtonForeground);
|
||||
}
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
virtual ~nsDisplayButtonForeground() {
|
||||
MOZ_COUNT_DTOR(nsDisplayButtonForeground);
|
||||
}
|
||||
#endif
|
||||
|
||||
nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override;
|
||||
void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
|
||||
const nsDisplayItemGeometry* aGeometry,
|
||||
nsRegion *aInvalidRegion) override;
|
||||
virtual void Paint(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext* aCtx) override;
|
||||
NS_DISPLAY_DECL_NAME("ButtonForeground", TYPE_BUTTON_FOREGROUND)
|
||||
private:
|
||||
nsButtonFrameRenderer* mBFR;
|
||||
};
|
||||
|
||||
nsDisplayItemGeometry*
|
||||
nsDisplayButtonForeground::AllocateGeometry(nsDisplayListBuilder* aBuilder)
|
||||
{
|
||||
return new nsDisplayItemGenericImageGeometry(this, aBuilder);
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayButtonForeground::ComputeInvalidationRegion(
|
||||
nsDisplayListBuilder* aBuilder,
|
||||
const nsDisplayItemGeometry* aGeometry,
|
||||
nsRegion* aInvalidRegion)
|
||||
{
|
||||
auto geometry =
|
||||
static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
|
||||
|
||||
if (aBuilder->ShouldSyncDecodeImages() &&
|
||||
geometry->ShouldInvalidateToSyncDecodeImages()) {
|
||||
bool snap;
|
||||
aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
|
||||
}
|
||||
|
||||
nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
|
||||
}
|
||||
|
||||
void nsDisplayButtonForeground::Paint(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext* aCtx)
|
||||
{
|
||||
nsPresContext *presContext = mFrame->PresContext();
|
||||
const nsStyleDisplay *disp = mFrame->StyleDisplay();
|
||||
if (!mFrame->IsThemed(disp) ||
|
||||
!presContext->GetTheme()->ThemeDrawsFocusForWidget(disp->mAppearance)) {
|
||||
nsRect r = nsRect(ToReferenceFrame(), mFrame->GetSize());
|
||||
|
||||
// Draw the focus and outline borders.
|
||||
DrawResult result =
|
||||
mBFR->PaintOutlineAndFocusBorders(aBuilder, presContext, *aCtx,
|
||||
mVisibleRect, r);
|
||||
|
||||
nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsButtonFrameRenderer::DisplayButton(nsDisplayListBuilder* aBuilder,
|
||||
nsDisplayList* aBackground,
|
||||
nsDisplayList* aForeground)
|
||||
{
|
||||
if (mFrame->StyleEffects()->mBoxShadow) {
|
||||
aBackground->AppendNewToTop(new (aBuilder)
|
||||
nsDisplayButtonBoxShadowOuter(aBuilder, this));
|
||||
}
|
||||
|
||||
nsRect buttonRect;
|
||||
GetButtonRect(mFrame->GetRectRelativeToSelf(), buttonRect);
|
||||
|
||||
nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
|
||||
aBuilder, mFrame, buttonRect, aBackground);
|
||||
|
||||
aBackground->AppendNewToTop(new (aBuilder)
|
||||
nsDisplayButtonBorder(aBuilder, this));
|
||||
|
||||
// Only display focus rings if we actually have them. Since at most one
|
||||
// button would normally display a focus ring, most buttons won't have them.
|
||||
if ((mOuterFocusStyle && mOuterFocusStyle->StyleBorder()->HasBorder()) ||
|
||||
(mInnerFocusStyle && mInnerFocusStyle->StyleBorder()->HasBorder())) {
|
||||
aForeground->AppendNewToTop(new (aBuilder)
|
||||
nsDisplayButtonForeground(aBuilder, this));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
DrawResult
|
||||
nsButtonFrameRenderer::PaintOutlineAndFocusBorders(
|
||||
nsDisplayListBuilder* aBuilder,
|
||||
nsPresContext* aPresContext,
|
||||
nsRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsRect& aRect)
|
||||
{
|
||||
// once we have all that we'll draw the focus if we have it. We will
|
||||
// need to draw 2 focuses, the inner and the outer. This is so we
|
||||
// can do any kind of look and feel. Some buttons have focus on the
|
||||
// outside like mac and motif. While others like windows have it
|
||||
// inside (dotted line). Usually only one will be specifed. But I
|
||||
// guess you could have both if you wanted to.
|
||||
|
||||
nsRect rect;
|
||||
|
||||
PaintBorderFlags flags = aBuilder->ShouldSyncDecodeImages()
|
||||
? PaintBorderFlags::SYNC_DECODE_IMAGES
|
||||
: PaintBorderFlags();
|
||||
|
||||
DrawResult result = DrawResult::SUCCESS;
|
||||
|
||||
if (mOuterFocusStyle) {
|
||||
// ---------- paint the outer focus border -------------
|
||||
|
||||
GetButtonOuterFocusRect(aRect, rect);
|
||||
|
||||
result &=
|
||||
nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, mFrame,
|
||||
aDirtyRect, rect, mOuterFocusStyle, flags);
|
||||
}
|
||||
|
||||
if (mInnerFocusStyle) {
|
||||
// ---------- paint the inner focus border -------------
|
||||
|
||||
GetButtonInnerFocusRect(aRect, rect);
|
||||
|
||||
result &=
|
||||
nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, mFrame,
|
||||
aDirtyRect, rect, mInnerFocusStyle, flags);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DrawResult
|
||||
nsButtonFrameRenderer::PaintBorder(
|
||||
nsDisplayListBuilder* aBuilder,
|
||||
nsPresContext* aPresContext,
|
||||
nsRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsRect& aRect)
|
||||
{
|
||||
// get the button rect this is inside the focus and outline rects
|
||||
nsRect buttonRect;
|
||||
GetButtonRect(aRect, buttonRect);
|
||||
|
||||
nsStyleContext* context = mFrame->StyleContext();
|
||||
|
||||
PaintBorderFlags borderFlags = aBuilder->ShouldSyncDecodeImages()
|
||||
? PaintBorderFlags::SYNC_DECODE_IMAGES
|
||||
: PaintBorderFlags();
|
||||
|
||||
nsCSSRendering::PaintBoxShadowInner(aPresContext, aRenderingContext,
|
||||
mFrame, buttonRect);
|
||||
|
||||
DrawResult result =
|
||||
nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, mFrame,
|
||||
aDirtyRect, buttonRect, context, borderFlags);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsButtonFrameRenderer::GetButtonOuterFocusRect(const nsRect& aRect, nsRect& focusRect)
|
||||
{
|
||||
focusRect = aRect;
|
||||
}
|
||||
|
||||
void
|
||||
nsButtonFrameRenderer::GetButtonRect(const nsRect& aRect, nsRect& r)
|
||||
{
|
||||
r = aRect;
|
||||
r.Deflate(GetButtonOuterFocusBorderAndPadding());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsButtonFrameRenderer::GetButtonInnerFocusRect(const nsRect& aRect, nsRect& focusRect)
|
||||
{
|
||||
GetButtonRect(aRect, focusRect);
|
||||
focusRect.Deflate(GetButtonBorderAndPadding());
|
||||
focusRect.Deflate(GetButtonInnerFocusMargin());
|
||||
}
|
||||
|
||||
|
||||
nsMargin
|
||||
nsButtonFrameRenderer::GetButtonOuterFocusBorderAndPadding()
|
||||
{
|
||||
nsMargin result(0,0,0,0);
|
||||
|
||||
if (mOuterFocusStyle) {
|
||||
mOuterFocusStyle->StylePadding()->GetPadding(result);
|
||||
result += mOuterFocusStyle->StyleBorder()->GetComputedBorder();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
nsMargin
|
||||
nsButtonFrameRenderer::GetButtonBorderAndPadding()
|
||||
{
|
||||
return mFrame->GetUsedBorderAndPadding();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of the buttons border this is the union of the normal and disabled borders.
|
||||
*/
|
||||
nsMargin
|
||||
nsButtonFrameRenderer::GetButtonInnerFocusMargin()
|
||||
{
|
||||
nsMargin innerFocusMargin(0,0,0,0);
|
||||
|
||||
if (mInnerFocusStyle) {
|
||||
const nsStyleMargin* margin = mInnerFocusStyle->StyleMargin();
|
||||
margin->GetMargin(innerFocusMargin);
|
||||
}
|
||||
|
||||
return innerFocusMargin;
|
||||
}
|
||||
|
||||
nsMargin
|
||||
nsButtonFrameRenderer::GetButtonInnerFocusBorderAndPadding()
|
||||
{
|
||||
nsMargin result(0,0,0,0);
|
||||
|
||||
if (mInnerFocusStyle) {
|
||||
mInnerFocusStyle->StylePadding()->GetPadding(result);
|
||||
result += mInnerFocusStyle->StyleBorder()->GetComputedBorder();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// gets all the focus borders and padding that will be added to the regular border
|
||||
nsMargin
|
||||
nsButtonFrameRenderer::GetAddedButtonBorderAndPadding()
|
||||
{
|
||||
return GetButtonOuterFocusBorderAndPadding() + GetButtonInnerFocusMargin() + GetButtonInnerFocusBorderAndPadding();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this when styles change
|
||||
*/
|
||||
void
|
||||
nsButtonFrameRenderer::ReResolveStyles(nsPresContext* aPresContext)
|
||||
{
|
||||
// get all the styles
|
||||
nsStyleContext* context = mFrame->StyleContext();
|
||||
StyleSetHandle styleSet = aPresContext->StyleSet();
|
||||
|
||||
#ifdef DEBUG
|
||||
if (mInnerFocusStyle) {
|
||||
mInnerFocusStyle->FrameRelease();
|
||||
}
|
||||
if (mOuterFocusStyle) {
|
||||
mOuterFocusStyle->FrameRelease();
|
||||
}
|
||||
#endif
|
||||
|
||||
// style for the inner such as a dotted line (Windows)
|
||||
mInnerFocusStyle =
|
||||
styleSet->ProbePseudoElementStyle(mFrame->GetContent()->AsElement(),
|
||||
CSSPseudoElementType::mozFocusInner,
|
||||
context);
|
||||
|
||||
// style for outer focus like a ridged border (MAC).
|
||||
mOuterFocusStyle =
|
||||
styleSet->ProbePseudoElementStyle(mFrame->GetContent()->AsElement(),
|
||||
CSSPseudoElementType::mozFocusOuter,
|
||||
context);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (mInnerFocusStyle) {
|
||||
mInnerFocusStyle->FrameAddRef();
|
||||
}
|
||||
if (mOuterFocusStyle) {
|
||||
mOuterFocusStyle->FrameAddRef();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
nsStyleContext*
|
||||
nsButtonFrameRenderer::GetStyleContext(int32_t aIndex) const
|
||||
{
|
||||
switch (aIndex) {
|
||||
case NS_BUTTON_RENDERER_FOCUS_INNER_CONTEXT_INDEX:
|
||||
return mInnerFocusStyle;
|
||||
case NS_BUTTON_RENDERER_FOCUS_OUTER_CONTEXT_INDEX:
|
||||
return mOuterFocusStyle;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsButtonFrameRenderer::SetStyleContext(int32_t aIndex, nsStyleContext* aStyleContext)
|
||||
{
|
||||
switch (aIndex) {
|
||||
case NS_BUTTON_RENDERER_FOCUS_INNER_CONTEXT_INDEX:
|
||||
#ifdef DEBUG
|
||||
if (mInnerFocusStyle) {
|
||||
mInnerFocusStyle->FrameRelease();
|
||||
}
|
||||
#endif
|
||||
mInnerFocusStyle = aStyleContext;
|
||||
break;
|
||||
case NS_BUTTON_RENDERER_FOCUS_OUTER_CONTEXT_INDEX:
|
||||
#ifdef DEBUG
|
||||
if (mOuterFocusStyle) {
|
||||
mOuterFocusStyle->FrameRelease();
|
||||
}
|
||||
#endif
|
||||
mOuterFocusStyle = aStyleContext;
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
aStyleContext->FrameAddRef();
|
||||
#endif
|
||||
}
|
||||
88
layout/forms/nsButtonFrameRenderer.h
Normal file
88
layout/forms/nsButtonFrameRenderer.h
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsButtonFrameRenderer_h___
|
||||
#define nsButtonFrameRenderer_h___
|
||||
|
||||
#include "imgIContainer.h"
|
||||
#include "nsMargin.h"
|
||||
|
||||
class nsIFrame;
|
||||
class nsFrame;
|
||||
class nsDisplayList;
|
||||
class nsDisplayListBuilder;
|
||||
class nsPresContext;
|
||||
class nsRenderingContext;
|
||||
struct nsRect;
|
||||
class nsStyleContext;
|
||||
|
||||
|
||||
#define NS_BUTTON_RENDERER_FOCUS_INNER_CONTEXT_INDEX 0
|
||||
#define NS_BUTTON_RENDERER_FOCUS_OUTER_CONTEXT_INDEX 1
|
||||
#define NS_BUTTON_RENDERER_LAST_CONTEXT_INDEX NS_BUTTON_RENDERER_FOCUS_OUTER_CONTEXT_INDEX
|
||||
|
||||
class nsButtonFrameRenderer {
|
||||
typedef mozilla::image::DrawResult DrawResult;
|
||||
|
||||
public:
|
||||
|
||||
nsButtonFrameRenderer();
|
||||
~nsButtonFrameRenderer();
|
||||
|
||||
/**
|
||||
* Create display list items for the button
|
||||
*/
|
||||
nsresult DisplayButton(nsDisplayListBuilder* aBuilder,
|
||||
nsDisplayList* aBackground, nsDisplayList* aForeground);
|
||||
|
||||
|
||||
DrawResult PaintOutlineAndFocusBorders(nsDisplayListBuilder* aBuilder,
|
||||
nsPresContext* aPresContext,
|
||||
nsRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsRect& aRect);
|
||||
|
||||
DrawResult PaintBorder(nsDisplayListBuilder* aBuilder,
|
||||
nsPresContext* aPresContext,
|
||||
nsRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsRect& aRect);
|
||||
|
||||
void SetFrame(nsFrame* aFrame, nsPresContext* aPresContext);
|
||||
|
||||
void SetDisabled(bool aDisabled, bool notify);
|
||||
|
||||
bool isActive();
|
||||
bool isDisabled();
|
||||
|
||||
void GetButtonOuterFocusRect(const nsRect& aRect, nsRect& aResult);
|
||||
void GetButtonRect(const nsRect& aRect, nsRect& aResult);
|
||||
void GetButtonInnerFocusRect(const nsRect& aRect, nsRect& aResult);
|
||||
nsMargin GetButtonOuterFocusBorderAndPadding();
|
||||
nsMargin GetButtonBorderAndPadding();
|
||||
nsMargin GetButtonInnerFocusMargin();
|
||||
nsMargin GetButtonInnerFocusBorderAndPadding();
|
||||
nsMargin GetAddedButtonBorderAndPadding();
|
||||
|
||||
nsStyleContext* GetStyleContext(int32_t aIndex) const;
|
||||
void SetStyleContext(int32_t aIndex, nsStyleContext* aStyleContext);
|
||||
void ReResolveStyles(nsPresContext* aPresContext);
|
||||
|
||||
nsIFrame* GetFrame();
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
|
||||
// cached styles for focus and outline.
|
||||
RefPtr<nsStyleContext> mInnerFocusStyle;
|
||||
RefPtr<nsStyleContext> mOuterFocusStyle;
|
||||
|
||||
nsFrame* mFrame;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
147
layout/forms/nsColorControlFrame.cpp
Normal file
147
layout/forms/nsColorControlFrame.cpp
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsColorControlFrame.h"
|
||||
|
||||
#include "nsContentCreatorFunctions.h"
|
||||
#include "nsContentList.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
#include "nsFormControlFrame.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsIDOMHTMLInputElement.h"
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsIFormControl.h"
|
||||
#include "mozilla/StyleSetHandle.h"
|
||||
#include "mozilla/StyleSetHandleInlines.h"
|
||||
#include "nsIDocument.h"
|
||||
|
||||
using mozilla::dom::Element;
|
||||
|
||||
nsColorControlFrame::nsColorControlFrame(nsStyleContext* aContext)
|
||||
: nsHTMLButtonControlFrame(aContext)
|
||||
{
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
NS_NewColorControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
|
||||
{
|
||||
return new (aPresShell) nsColorControlFrame(aContext);
|
||||
}
|
||||
|
||||
NS_IMPL_FRAMEARENA_HELPERS(nsColorControlFrame)
|
||||
|
||||
NS_QUERYFRAME_HEAD(nsColorControlFrame)
|
||||
NS_QUERYFRAME_ENTRY(nsColorControlFrame)
|
||||
NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
|
||||
NS_QUERYFRAME_TAIL_INHERITING(nsHTMLButtonControlFrame)
|
||||
|
||||
|
||||
void nsColorControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
|
||||
{
|
||||
nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false);
|
||||
nsContentUtils::DestroyAnonymousContent(&mColorContent);
|
||||
nsHTMLButtonControlFrame::DestroyFrom(aDestructRoot);
|
||||
}
|
||||
|
||||
nsIAtom*
|
||||
nsColorControlFrame::GetType() const
|
||||
{
|
||||
return nsGkAtoms::colorControlFrame;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
nsresult
|
||||
nsColorControlFrame::GetFrameName(nsAString& aResult) const
|
||||
{
|
||||
return MakeFrameName(NS_LITERAL_STRING("ColorControl"), aResult);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Create the color area for the button.
|
||||
// The frame will be generated by the frame constructor.
|
||||
nsresult
|
||||
nsColorControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
|
||||
{
|
||||
nsCOMPtr<nsIDocument> doc = mContent->GetComposedDoc();
|
||||
mColorContent = doc->CreateHTMLElement(nsGkAtoms::div);
|
||||
|
||||
// Mark the element to be native anonymous before setting any attributes.
|
||||
mColorContent->SetIsNativeAnonymousRoot();
|
||||
|
||||
nsresult rv = UpdateColor();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
CSSPseudoElementType pseudoType = CSSPseudoElementType::mozColorSwatch;
|
||||
RefPtr<nsStyleContext> newStyleContext = PresContext()->StyleSet()->
|
||||
ResolvePseudoElementStyle(mContent->AsElement(), pseudoType,
|
||||
StyleContext(), mColorContent->AsElement());
|
||||
if (!aElements.AppendElement(ContentInfo(mColorContent, newStyleContext))) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsColorControlFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
|
||||
uint32_t aFilter)
|
||||
{
|
||||
if (mColorContent) {
|
||||
aElements.AppendElement(mColorContent);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsColorControlFrame::UpdateColor()
|
||||
{
|
||||
// Get the color from the "value" property of our content; it will return the
|
||||
// default color (through the sanitization algorithm) if there is none.
|
||||
nsAutoString color;
|
||||
nsCOMPtr<nsIDOMHTMLInputElement> elt = do_QueryInterface(mContent);
|
||||
elt->GetValue(color);
|
||||
MOZ_ASSERT(!color.IsEmpty(),
|
||||
"Content node's GetValue() should return a valid color string "
|
||||
"(the default color, in case no valid color is set)");
|
||||
|
||||
// Set the background-color style property of the swatch element to this color
|
||||
return mColorContent->SetAttr(kNameSpaceID_None, nsGkAtoms::style,
|
||||
NS_LITERAL_STRING("background-color:") + color, true);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsColorControlFrame::AttributeChanged(int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
{
|
||||
NS_ASSERTION(mColorContent, "The color div must exist");
|
||||
|
||||
// If the value attribute is set, update the color box, but only if we're
|
||||
// still a color control, which might not be the case if the type attribute
|
||||
// was removed/changed.
|
||||
nsCOMPtr<nsIFormControl> fctrl = do_QueryInterface(GetContent());
|
||||
if (fctrl->GetType() == NS_FORM_INPUT_COLOR &&
|
||||
aNameSpaceID == kNameSpaceID_None && nsGkAtoms::value == aAttribute) {
|
||||
UpdateColor();
|
||||
}
|
||||
return nsHTMLButtonControlFrame::AttributeChanged(aNameSpaceID, aAttribute,
|
||||
aModType);
|
||||
}
|
||||
|
||||
nsContainerFrame*
|
||||
nsColorControlFrame::GetContentInsertionFrame()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
Element*
|
||||
nsColorControlFrame::GetPseudoElement(CSSPseudoElementType aType)
|
||||
{
|
||||
if (aType == CSSPseudoElementType::mozColorSwatch) {
|
||||
return mColorContent;
|
||||
}
|
||||
|
||||
return nsContainerFrame::GetPseudoElement(aType);
|
||||
}
|
||||
65
layout/forms/nsColorControlFrame.h
Normal file
65
layout/forms/nsColorControlFrame.h
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsColorControlFrame_h___
|
||||
#define nsColorControlFrame_h___
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsHTMLButtonControlFrame.h"
|
||||
#include "nsIAnonymousContentCreator.h"
|
||||
|
||||
namespace mozilla {
|
||||
enum class CSSPseudoElementType : uint8_t;
|
||||
} // namespace mozilla
|
||||
|
||||
// Class which implements the input type=color
|
||||
|
||||
class nsColorControlFrame final : public nsHTMLButtonControlFrame,
|
||||
public nsIAnonymousContentCreator
|
||||
{
|
||||
typedef mozilla::CSSPseudoElementType CSSPseudoElementType;
|
||||
typedef mozilla::dom::Element Element;
|
||||
|
||||
public:
|
||||
friend nsIFrame* NS_NewColorControlFrame(nsIPresShell* aPresShell,
|
||||
nsStyleContext* aContext);
|
||||
|
||||
virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
|
||||
|
||||
NS_DECL_QUERYFRAME_TARGET(nsColorControlFrame)
|
||||
NS_DECL_QUERYFRAME
|
||||
NS_DECL_FRAMEARENA_HELPERS
|
||||
|
||||
virtual nsIAtom* GetType() const override;
|
||||
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
virtual nsresult GetFrameName(nsAString& aResult) const override;
|
||||
#endif
|
||||
|
||||
// nsIAnonymousContentCreator
|
||||
virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
|
||||
virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
|
||||
uint32_t aFilter) override;
|
||||
|
||||
// nsIFrame
|
||||
virtual nsresult AttributeChanged(int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType) override;
|
||||
virtual bool IsLeaf() const override { return true; }
|
||||
virtual nsContainerFrame* GetContentInsertionFrame() override;
|
||||
|
||||
virtual Element* GetPseudoElement(CSSPseudoElementType aType) override;
|
||||
|
||||
// Refresh the color swatch, using associated input's value
|
||||
nsresult UpdateColor();
|
||||
|
||||
private:
|
||||
explicit nsColorControlFrame(nsStyleContext* aContext);
|
||||
|
||||
nsCOMPtr<Element> mColorContent;
|
||||
};
|
||||
|
||||
|
||||
#endif // nsColorControlFrame_h___
|
||||
1715
layout/forms/nsComboboxControlFrame.cpp
Normal file
1715
layout/forms/nsComboboxControlFrame.cpp
Normal file
File diff suppressed because it is too large
Load diff
328
layout/forms/nsComboboxControlFrame.h
Normal file
328
layout/forms/nsComboboxControlFrame.h
Normal file
|
|
@ -0,0 +1,328 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsComboboxControlFrame_h___
|
||||
#define nsComboboxControlFrame_h___
|
||||
|
||||
#ifdef DEBUG_evaughan
|
||||
//#define DEBUG_rods
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_rods
|
||||
//#define DO_REFLOW_DEBUG
|
||||
//#define DO_REFLOW_COUNTER
|
||||
//#define DO_UNCONSTRAINED_CHECK
|
||||
//#define DO_PIXELS
|
||||
//#define DO_NEW_REFLOW
|
||||
#endif
|
||||
|
||||
//Mark used to indicate when onchange has been fired for current combobox item
|
||||
#define NS_SKIP_NOTIFY_INDEX -2
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsBlockFrame.h"
|
||||
#include "nsIFormControlFrame.h"
|
||||
#include "nsIComboboxControlFrame.h"
|
||||
#include "nsIAnonymousContentCreator.h"
|
||||
#include "nsISelectControlFrame.h"
|
||||
#include "nsIRollupListener.h"
|
||||
#include "nsIStatefulFrame.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
class nsStyleContext;
|
||||
class nsIListControlFrame;
|
||||
class nsComboboxDisplayFrame;
|
||||
class nsIDOMEventListener;
|
||||
class nsIScrollableFrame;
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
class DrawTarget;
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
class nsComboboxControlFrame final : public nsBlockFrame,
|
||||
public nsIFormControlFrame,
|
||||
public nsIComboboxControlFrame,
|
||||
public nsIAnonymousContentCreator,
|
||||
public nsISelectControlFrame,
|
||||
public nsIRollupListener,
|
||||
public nsIStatefulFrame
|
||||
{
|
||||
typedef mozilla::gfx::DrawTarget DrawTarget;
|
||||
|
||||
public:
|
||||
friend nsContainerFrame* NS_NewComboboxControlFrame(nsIPresShell* aPresShell,
|
||||
nsStyleContext* aContext,
|
||||
nsFrameState aFlags);
|
||||
friend class nsComboboxDisplayFrame;
|
||||
|
||||
explicit nsComboboxControlFrame(nsStyleContext* aContext);
|
||||
~nsComboboxControlFrame();
|
||||
|
||||
NS_DECL_QUERYFRAME
|
||||
NS_DECL_FRAMEARENA_HELPERS
|
||||
|
||||
// nsIAnonymousContentCreator
|
||||
virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
|
||||
virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
|
||||
uint32_t aFilter) override;
|
||||
virtual nsIFrame* CreateFrameFor(nsIContent* aContent) override;
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
virtual mozilla::a11y::AccType AccessibleType() override;
|
||||
#endif
|
||||
|
||||
virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) override;
|
||||
|
||||
virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext) override;
|
||||
|
||||
virtual void Reflow(nsPresContext* aCX,
|
||||
ReflowOutput& aDesiredSize,
|
||||
const ReflowInput& aReflowInput,
|
||||
nsReflowStatus& aStatus) override;
|
||||
|
||||
virtual nsresult HandleEvent(nsPresContext* aPresContext,
|
||||
mozilla::WidgetGUIEvent* aEvent,
|
||||
nsEventStatus* aEventStatus) override;
|
||||
|
||||
virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists) override;
|
||||
|
||||
void PaintFocus(DrawTarget& aDrawTarget, nsPoint aPt);
|
||||
|
||||
// XXXbz this is only needed to prevent the quirk percent height stuff from
|
||||
// leaking out of the combobox. We may be able to get rid of this as more
|
||||
// things move to IsFrameOfType.
|
||||
virtual nsIAtom* GetType() const override;
|
||||
|
||||
virtual bool IsFrameOfType(uint32_t aFlags) const override
|
||||
{
|
||||
return nsBlockFrame::IsFrameOfType(aFlags &
|
||||
~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
|
||||
}
|
||||
|
||||
virtual nsIScrollableFrame* GetScrollTargetFrame() override {
|
||||
return do_QueryFrame(mDropdownFrame);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
virtual nsresult GetFrameName(nsAString& aResult) const override;
|
||||
#endif
|
||||
virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
|
||||
virtual void SetInitialChildList(ChildListID aListID,
|
||||
nsFrameList& aChildList) override;
|
||||
virtual const nsFrameList& GetChildList(ChildListID aListID) const override;
|
||||
virtual void GetChildLists(nsTArray<ChildList>* aLists) const override;
|
||||
|
||||
virtual nsContainerFrame* GetContentInsertionFrame() override;
|
||||
|
||||
// nsIFormControlFrame
|
||||
virtual nsresult SetFormProperty(nsIAtom* aName, const nsAString& aValue) override;
|
||||
/**
|
||||
* Inform the control that it got (or lost) focus.
|
||||
* If it lost focus, the dropdown menu will be rolled up if needed,
|
||||
* and FireOnChange() will be called.
|
||||
* @param aOn true if got focus, false if lost focus.
|
||||
* @param aRepaint if true then force repaint (NOTE: we always force repaint currently)
|
||||
* @note This method might destroy |this|.
|
||||
*/
|
||||
virtual void SetFocus(bool aOn, bool aRepaint) override;
|
||||
|
||||
//nsIComboboxControlFrame
|
||||
virtual bool IsDroppedDown() override { return mDroppedDown; }
|
||||
/**
|
||||
* @note This method might destroy |this|.
|
||||
*/
|
||||
virtual void ShowDropDown(bool aDoDropDown) override;
|
||||
virtual nsIFrame* GetDropDown() override;
|
||||
virtual void SetDropDown(nsIFrame* aDropDownFrame) override;
|
||||
/**
|
||||
* @note This method might destroy |this|.
|
||||
*/
|
||||
virtual void RollupFromList() override;
|
||||
|
||||
/**
|
||||
* Return the available space before and after this frame for
|
||||
* placing the drop-down list, and the current 2D translation.
|
||||
* Note that either or both can be less than or equal to zero,
|
||||
* if both are then the drop-down should be closed.
|
||||
*/
|
||||
void GetAvailableDropdownSpace(mozilla::WritingMode aWM,
|
||||
nscoord* aBefore,
|
||||
nscoord* aAfter,
|
||||
mozilla::LogicalPoint* aTranslation);
|
||||
virtual int32_t GetIndexOfDisplayArea() override;
|
||||
/**
|
||||
* @note This method might destroy |this|.
|
||||
*/
|
||||
NS_IMETHOD RedisplaySelectedText() override;
|
||||
virtual int32_t UpdateRecentIndex(int32_t aIndex) override;
|
||||
virtual void OnContentReset() override;
|
||||
|
||||
|
||||
bool IsOpenInParentProcess() override
|
||||
{
|
||||
return mIsOpenInParentProcess;
|
||||
}
|
||||
|
||||
void SetOpenInParentProcess(bool aVal) override
|
||||
{
|
||||
mIsOpenInParentProcess = aVal;
|
||||
}
|
||||
|
||||
// nsISelectControlFrame
|
||||
NS_IMETHOD AddOption(int32_t index) override;
|
||||
NS_IMETHOD RemoveOption(int32_t index) override;
|
||||
NS_IMETHOD DoneAddingChildren(bool aIsDone) override;
|
||||
NS_IMETHOD OnOptionSelected(int32_t aIndex, bool aSelected) override;
|
||||
NS_IMETHOD OnSetSelectedIndex(int32_t aOldIndex, int32_t aNewIndex) override;
|
||||
|
||||
//nsIRollupListener
|
||||
/**
|
||||
* Hide the dropdown menu and stop capturing mouse events.
|
||||
* @note This method might destroy |this|.
|
||||
*/
|
||||
virtual bool Rollup(uint32_t aCount, bool aFlush,
|
||||
const nsIntPoint* pos, nsIContent** aLastRolledUp) override;
|
||||
virtual void NotifyGeometryChange() override;
|
||||
|
||||
/**
|
||||
* A combobox should roll up if a mousewheel event happens outside of
|
||||
* the popup area.
|
||||
*/
|
||||
virtual bool ShouldRollupOnMouseWheelEvent() override
|
||||
{ return true; }
|
||||
|
||||
virtual bool ShouldConsumeOnMouseWheelEvent() override
|
||||
{ return false; }
|
||||
|
||||
/**
|
||||
* A combobox should not roll up if activated by a mouse activate message
|
||||
* (eg. X-mouse).
|
||||
*/
|
||||
virtual bool ShouldRollupOnMouseActivate() override
|
||||
{ return false; }
|
||||
|
||||
virtual uint32_t GetSubmenuWidgetChain(nsTArray<nsIWidget*> *aWidgetChain) override
|
||||
{ return 0; }
|
||||
|
||||
virtual nsIWidget* GetRollupWidget() override;
|
||||
|
||||
//nsIStatefulFrame
|
||||
NS_IMETHOD SaveState(nsPresState** aState) override;
|
||||
NS_IMETHOD RestoreState(nsPresState* aState) override;
|
||||
NS_IMETHOD GenerateStateKey(nsIContent* aContent,
|
||||
nsIDocument* aDocument,
|
||||
nsACString& aKey) override;
|
||||
|
||||
static bool ToolkitHasNativePopup();
|
||||
|
||||
protected:
|
||||
friend class RedisplayTextEvent;
|
||||
friend class nsAsyncResize;
|
||||
friend class nsResizeDropdownAtFinalPosition;
|
||||
|
||||
// Utilities
|
||||
void ReflowDropdown(nsPresContext* aPresContext,
|
||||
const ReflowInput& aReflowInput);
|
||||
|
||||
enum DropDownPositionState {
|
||||
// can't show the dropdown at its current position
|
||||
eDropDownPositionSuppressed,
|
||||
// a resize reflow is pending, don't show it yet
|
||||
eDropDownPositionPendingResize,
|
||||
// the dropdown has its final size and position and can be displayed here
|
||||
eDropDownPositionFinal
|
||||
};
|
||||
DropDownPositionState AbsolutelyPositionDropDown();
|
||||
|
||||
// Helper for GetMinISize/GetPrefISize
|
||||
nscoord GetIntrinsicISize(nsRenderingContext* aRenderingContext,
|
||||
nsLayoutUtils::IntrinsicISizeType aType);
|
||||
|
||||
class RedisplayTextEvent : public mozilla::Runnable {
|
||||
public:
|
||||
NS_DECL_NSIRUNNABLE
|
||||
explicit RedisplayTextEvent(nsComboboxControlFrame *c) : mControlFrame(c) {}
|
||||
void Revoke() { mControlFrame = nullptr; }
|
||||
private:
|
||||
nsComboboxControlFrame *mControlFrame;
|
||||
};
|
||||
|
||||
/**
|
||||
* Show or hide the dropdown list.
|
||||
* @note This method might destroy |this|.
|
||||
*/
|
||||
void ShowPopup(bool aShowPopup);
|
||||
|
||||
/**
|
||||
* Show or hide the dropdown list.
|
||||
* @param aShowList true to show, false to hide the dropdown.
|
||||
* @note This method might destroy |this|.
|
||||
* @return false if this frame is destroyed, true if still alive.
|
||||
*/
|
||||
bool ShowList(bool aShowList);
|
||||
void CheckFireOnChange();
|
||||
void FireValueChangeEvent();
|
||||
nsresult RedisplayText(int32_t aIndex);
|
||||
void HandleRedisplayTextEvent();
|
||||
void ActuallyDisplayText(bool aNotify);
|
||||
|
||||
private:
|
||||
// If our total transform to the root frame of the root document is only a 2d
|
||||
// translation then return that translation, otherwise returns (0,0).
|
||||
nsPoint GetCSSTransformTranslation();
|
||||
|
||||
protected:
|
||||
nsFrameList mPopupFrames; // additional named child list
|
||||
nsCOMPtr<nsIContent> mDisplayContent; // Anonymous content used to display the current selection
|
||||
nsCOMPtr<nsIContent> mButtonContent; // Anonymous content for the button
|
||||
nsContainerFrame* mDisplayFrame; // frame to display selection
|
||||
nsIFrame* mButtonFrame; // button frame
|
||||
nsIFrame* mDropdownFrame; // dropdown list frame
|
||||
nsIListControlFrame * mListControlFrame; // ListControl Interface for the dropdown frame
|
||||
|
||||
// The inline size of our display area. Used by that frame's reflow
|
||||
// to size to the full inline size except the drop-marker.
|
||||
nscoord mDisplayISize;
|
||||
|
||||
nsRevocableEventPtr<RedisplayTextEvent> mRedisplayTextEvent;
|
||||
|
||||
int32_t mRecentSelectedIndex;
|
||||
int32_t mDisplayedIndex;
|
||||
nsString mDisplayedOptionText;
|
||||
|
||||
// make someone to listen to the button. If its programmatically pressed by someone like Accessibility
|
||||
// then open or close the combo box.
|
||||
nsCOMPtr<nsIDOMEventListener> mButtonListener;
|
||||
|
||||
// The last y-positions used for estimating available space before and
|
||||
// after for the dropdown list in GetAvailableDropdownSpace. These are
|
||||
// reset to nscoord_MIN in AbsolutelyPositionDropDown when placing the
|
||||
// dropdown at its actual position. The GetAvailableDropdownSpace call
|
||||
// from nsListControlFrame::ReflowAsDropdown use the last position.
|
||||
nscoord mLastDropDownBeforeScreenBCoord;
|
||||
nscoord mLastDropDownAfterScreenBCoord;
|
||||
// Current state of the dropdown list, true is dropped down.
|
||||
bool mDroppedDown;
|
||||
// See comment in HandleRedisplayTextEvent().
|
||||
bool mInRedisplayText;
|
||||
// Acting on ShowDropDown(true) is delayed until we're focused.
|
||||
bool mDelayedShowDropDown;
|
||||
|
||||
bool mIsOpenInParentProcess;
|
||||
|
||||
// static class data member for Bug 32920
|
||||
// only one control can be focused at a time
|
||||
static nsComboboxControlFrame* sFocused;
|
||||
|
||||
#ifdef DO_REFLOW_COUNTER
|
||||
int32_t mReflowId;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
414
layout/forms/nsDateTimeControlFrame.cpp
Normal file
414
layout/forms/nsDateTimeControlFrame.cpp
Normal file
|
|
@ -0,0 +1,414 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* This frame type is used for input type=date, time, month, week, and
|
||||
* datetime-local.
|
||||
*/
|
||||
|
||||
#include "nsDateTimeControlFrame.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsFormControlFrame.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsContentCreatorFunctions.h"
|
||||
#include "nsContentList.h"
|
||||
#include "mozilla/dom/HTMLInputElement.h"
|
||||
#include "nsNodeInfoManager.h"
|
||||
#include "nsIDateTimeInputArea.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIDOMHTMLInputElement.h"
|
||||
#include "nsIDOMMutationEvent.h"
|
||||
#include "jsapi.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
nsIFrame*
|
||||
NS_NewDateTimeControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
|
||||
{
|
||||
return new (aPresShell) nsDateTimeControlFrame(aContext);
|
||||
}
|
||||
|
||||
NS_IMPL_FRAMEARENA_HELPERS(nsDateTimeControlFrame)
|
||||
|
||||
NS_QUERYFRAME_HEAD(nsDateTimeControlFrame)
|
||||
NS_QUERYFRAME_ENTRY(nsDateTimeControlFrame)
|
||||
NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
|
||||
NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
|
||||
|
||||
nsDateTimeControlFrame::nsDateTimeControlFrame(nsStyleContext* aContext)
|
||||
: nsContainerFrame(aContext)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsDateTimeControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
|
||||
{
|
||||
nsContentUtils::DestroyAnonymousContent(&mInputAreaContent);
|
||||
nsContainerFrame::DestroyFrom(aDestructRoot);
|
||||
}
|
||||
|
||||
void
|
||||
nsDateTimeControlFrame::UpdateInputBoxValue()
|
||||
{
|
||||
nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
|
||||
do_QueryInterface(mInputAreaContent);
|
||||
if (inputAreaContent) {
|
||||
inputAreaContent->NotifyInputElementValueChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDateTimeControlFrame::SetValueFromPicker(const DateTimeValue& aValue)
|
||||
{
|
||||
nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
|
||||
do_QueryInterface(mInputAreaContent);
|
||||
if (inputAreaContent) {
|
||||
AutoJSAPI api;
|
||||
if (!api.Init(mContent->OwnerDoc()->GetScopeObject())) {
|
||||
return;
|
||||
}
|
||||
|
||||
JSObject* wrapper = mContent->GetWrapper();
|
||||
if (!wrapper) {
|
||||
return;
|
||||
}
|
||||
|
||||
JSObject* scope = xpc::GetXBLScope(api.cx(), wrapper);
|
||||
AutoJSAPI jsapi;
|
||||
if (!scope || !jsapi.Init(scope)) {
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> jsValue(jsapi.cx());
|
||||
if (!ToJSValue(jsapi.cx(), aValue, &jsValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
inputAreaContent->SetValueFromPicker(jsValue);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDateTimeControlFrame::SetPickerState(bool aOpen)
|
||||
{
|
||||
nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
|
||||
do_QueryInterface(mInputAreaContent);
|
||||
if (inputAreaContent) {
|
||||
inputAreaContent->SetPickerState(aOpen);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDateTimeControlFrame::HandleFocusEvent()
|
||||
{
|
||||
nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
|
||||
do_QueryInterface(mInputAreaContent);
|
||||
if (inputAreaContent) {
|
||||
inputAreaContent->FocusInnerTextBox();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDateTimeControlFrame::HandleBlurEvent()
|
||||
{
|
||||
nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
|
||||
do_QueryInterface(mInputAreaContent);
|
||||
if (inputAreaContent) {
|
||||
inputAreaContent->BlurInnerTextBox();
|
||||
}
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsDateTimeControlFrame::GetMinISize(nsRenderingContext* aRenderingContext)
|
||||
{
|
||||
nscoord result;
|
||||
DISPLAY_MIN_WIDTH(this, result);
|
||||
|
||||
nsIFrame* kid = mFrames.FirstChild();
|
||||
if (kid) { // display:none?
|
||||
result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
|
||||
kid,
|
||||
nsLayoutUtils::MIN_ISIZE);
|
||||
} else {
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsDateTimeControlFrame::GetPrefISize(nsRenderingContext* aRenderingContext)
|
||||
{
|
||||
nscoord result;
|
||||
DISPLAY_PREF_WIDTH(this, result);
|
||||
|
||||
nsIFrame* kid = mFrames.FirstChild();
|
||||
if (kid) { // display:none?
|
||||
result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
|
||||
kid,
|
||||
nsLayoutUtils::PREF_ISIZE);
|
||||
} else {
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
nsDateTimeControlFrame::Reflow(nsPresContext* aPresContext,
|
||||
ReflowOutput& aDesiredSize,
|
||||
const ReflowInput& aReflowInput,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
MarkInReflow();
|
||||
|
||||
DO_GLOBAL_REFLOW_COUNT("nsDateTimeControlFrame");
|
||||
DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
|
||||
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
||||
("enter nsDateTimeControlFrame::Reflow: availSize=%d,%d",
|
||||
aReflowInput.AvailableWidth(),
|
||||
aReflowInput.AvailableHeight()));
|
||||
|
||||
NS_ASSERTION(mInputAreaContent, "The input area content must exist!");
|
||||
|
||||
const WritingMode myWM = aReflowInput.GetWritingMode();
|
||||
|
||||
// The ISize of our content box, which is the available ISize
|
||||
// for our anonymous content:
|
||||
const nscoord contentBoxISize = aReflowInput.ComputedISize();
|
||||
nscoord contentBoxBSize = aReflowInput.ComputedBSize();
|
||||
|
||||
// Figure out our border-box sizes as well (by adding borderPadding to
|
||||
// content-box sizes):
|
||||
const nscoord borderBoxISize = contentBoxISize +
|
||||
aReflowInput.ComputedLogicalBorderPadding().IStartEnd(myWM);
|
||||
|
||||
nscoord borderBoxBSize;
|
||||
if (contentBoxBSize != NS_INTRINSICSIZE) {
|
||||
borderBoxBSize = contentBoxBSize +
|
||||
aReflowInput.ComputedLogicalBorderPadding().BStartEnd(myWM);
|
||||
} // else, we'll figure out borderBoxBSize after we resolve contentBoxBSize.
|
||||
|
||||
nsIFrame* inputAreaFrame = mFrames.FirstChild();
|
||||
if (!inputAreaFrame) { // display:none?
|
||||
if (contentBoxBSize == NS_INTRINSICSIZE) {
|
||||
contentBoxBSize = 0;
|
||||
borderBoxBSize =
|
||||
aReflowInput.ComputedLogicalBorderPadding().BStartEnd(myWM);
|
||||
}
|
||||
} else {
|
||||
NS_ASSERTION(inputAreaFrame->GetContent() == mInputAreaContent,
|
||||
"What is this child doing here?");
|
||||
|
||||
ReflowOutput childDesiredSize(aReflowInput);
|
||||
|
||||
WritingMode wm = inputAreaFrame->GetWritingMode();
|
||||
LogicalSize availSize = aReflowInput.ComputedSize(wm);
|
||||
availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
|
||||
|
||||
ReflowInput childReflowOuput(aPresContext, aReflowInput,
|
||||
inputAreaFrame, availSize);
|
||||
|
||||
// Convert input area margin into my own writing-mode (in case it differs):
|
||||
LogicalMargin childMargin =
|
||||
childReflowOuput.ComputedLogicalMargin().ConvertTo(myWM, wm);
|
||||
|
||||
// offsets of input area frame within this frame:
|
||||
LogicalPoint
|
||||
childOffset(myWM,
|
||||
aReflowInput.ComputedLogicalBorderPadding().IStart(myWM) +
|
||||
childMargin.IStart(myWM),
|
||||
aReflowInput.ComputedLogicalBorderPadding().BStart(myWM) +
|
||||
childMargin.BStart(myWM));
|
||||
|
||||
nsReflowStatus childStatus;
|
||||
// We initially reflow the child with a dummy containerSize; positioning
|
||||
// will be fixed later.
|
||||
const nsSize dummyContainerSize;
|
||||
ReflowChild(inputAreaFrame, aPresContext, childDesiredSize,
|
||||
childReflowOuput, myWM, childOffset, dummyContainerSize, 0,
|
||||
childStatus);
|
||||
MOZ_ASSERT(NS_FRAME_IS_FULLY_COMPLETE(childStatus),
|
||||
"We gave our child unconstrained available block-size, "
|
||||
"so it should be complete");
|
||||
|
||||
nscoord childMarginBoxBSize =
|
||||
childDesiredSize.BSize(myWM) + childMargin.BStartEnd(myWM);
|
||||
|
||||
if (contentBoxBSize == NS_INTRINSICSIZE) {
|
||||
// We are intrinsically sized -- we should shrinkwrap the input area's
|
||||
// block-size:
|
||||
contentBoxBSize = childMarginBoxBSize;
|
||||
|
||||
// Make sure we obey min/max-bsize in the case when we're doing intrinsic
|
||||
// sizing (we get it for free when we have a non-intrinsic
|
||||
// aReflowInput.ComputedBSize()). Note that we do this before
|
||||
// adjusting for borderpadding, since ComputedMaxBSize and
|
||||
// ComputedMinBSize are content heights.
|
||||
contentBoxBSize =
|
||||
NS_CSS_MINMAX(contentBoxBSize,
|
||||
aReflowInput.ComputedMinBSize(),
|
||||
aReflowInput.ComputedMaxBSize());
|
||||
|
||||
borderBoxBSize = contentBoxBSize +
|
||||
aReflowInput.ComputedLogicalBorderPadding().BStartEnd(myWM);
|
||||
}
|
||||
|
||||
// Center child in block axis
|
||||
nscoord extraSpace = contentBoxBSize - childMarginBoxBSize;
|
||||
childOffset.B(myWM) += std::max(0, extraSpace / 2);
|
||||
|
||||
// Needed in FinishReflowChild, for logical-to-physical conversion:
|
||||
nsSize borderBoxSize = LogicalSize(myWM, borderBoxISize, borderBoxBSize).
|
||||
GetPhysicalSize(myWM);
|
||||
|
||||
// Place the child
|
||||
FinishReflowChild(inputAreaFrame, aPresContext, childDesiredSize,
|
||||
&childReflowOuput, myWM, childOffset, borderBoxSize, 0);
|
||||
|
||||
nsSize contentBoxSize =
|
||||
LogicalSize(myWM, contentBoxISize, contentBoxBSize).
|
||||
GetPhysicalSize(myWM);
|
||||
aDesiredSize.SetBlockStartAscent(
|
||||
childDesiredSize.BlockStartAscent() +
|
||||
inputAreaFrame->BStart(aReflowInput.GetWritingMode(),
|
||||
contentBoxSize));
|
||||
}
|
||||
|
||||
LogicalSize logicalDesiredSize(myWM, borderBoxISize, borderBoxBSize);
|
||||
aDesiredSize.SetSize(myWM, logicalDesiredSize);
|
||||
|
||||
aDesiredSize.SetOverflowAreasToDesiredBounds();
|
||||
|
||||
if (inputAreaFrame) {
|
||||
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, inputAreaFrame);
|
||||
}
|
||||
|
||||
FinishAndStoreOverflow(&aDesiredSize);
|
||||
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
|
||||
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
||||
("exit nsDateTimeControlFrame::Reflow: size=%d,%d",
|
||||
aDesiredSize.Width(), aDesiredSize.Height()));
|
||||
NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDateTimeControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
|
||||
{
|
||||
// Set up "datetimebox" XUL element which will be XBL-bound to the
|
||||
// actual controls.
|
||||
nsNodeInfoManager* nodeInfoManager =
|
||||
mContent->GetComposedDoc()->NodeInfoManager();
|
||||
RefPtr<NodeInfo> nodeInfo =
|
||||
nodeInfoManager->GetNodeInfo(nsGkAtoms::datetimebox, nullptr,
|
||||
kNameSpaceID_XUL, nsIDOMNode::ELEMENT_NODE);
|
||||
NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
NS_TrustedNewXULElement(getter_AddRefs(mInputAreaContent), nodeInfo.forget());
|
||||
aElements.AppendElement(mInputAreaContent);
|
||||
|
||||
// Propogate our tabindex.
|
||||
nsAutoString tabIndexStr;
|
||||
if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::tabindex, tabIndexStr)) {
|
||||
mInputAreaContent->SetAttr(kNameSpaceID_None, nsGkAtoms::tabindex,
|
||||
tabIndexStr, false);
|
||||
}
|
||||
|
||||
// Propagate our readonly state.
|
||||
nsAutoString readonly;
|
||||
if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::readonly, readonly)) {
|
||||
mInputAreaContent->SetAttr(kNameSpaceID_None, nsGkAtoms::readonly, readonly,
|
||||
false);
|
||||
}
|
||||
|
||||
SyncDisabledState();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsDateTimeControlFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
|
||||
uint32_t aFilter)
|
||||
{
|
||||
if (mInputAreaContent) {
|
||||
aElements.AppendElement(mInputAreaContent);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDateTimeControlFrame::SyncDisabledState()
|
||||
{
|
||||
EventStates eventStates = mContent->AsElement()->State();
|
||||
if (eventStates.HasState(NS_EVENT_STATE_DISABLED)) {
|
||||
mInputAreaContent->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled,
|
||||
EmptyString(), true);
|
||||
} else {
|
||||
mInputAreaContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, true);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDateTimeControlFrame::AttributeChanged(int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
{
|
||||
NS_ASSERTION(mInputAreaContent, "The input area content must exist!");
|
||||
|
||||
// nsGkAtoms::disabled is handled by SyncDisabledState
|
||||
if (aNameSpaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::value ||
|
||||
aAttribute == nsGkAtoms::readonly ||
|
||||
aAttribute == nsGkAtoms::tabindex) {
|
||||
MOZ_ASSERT(mContent->IsHTMLElement(nsGkAtoms::input), "bad cast");
|
||||
auto contentAsInputElem = static_cast<dom::HTMLInputElement*>(mContent);
|
||||
// If script changed the <input>'s type before setting these attributes
|
||||
// then we don't need to do anything since we are going to be reframed.
|
||||
if (contentAsInputElem->GetType() == NS_FORM_INPUT_TIME) {
|
||||
if (aAttribute == nsGkAtoms::value) {
|
||||
nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
|
||||
do_QueryInterface(mInputAreaContent);
|
||||
if (inputAreaContent) {
|
||||
nsContentUtils::AddScriptRunner(NewRunnableMethod(inputAreaContent,
|
||||
&nsIDateTimeInputArea::NotifyInputElementValueChanged));
|
||||
}
|
||||
} else {
|
||||
if (aModType == nsIDOMMutationEvent::REMOVAL) {
|
||||
mInputAreaContent->UnsetAttr(aNameSpaceID, aAttribute, true);
|
||||
} else {
|
||||
MOZ_ASSERT(aModType == nsIDOMMutationEvent::ADDITION ||
|
||||
aModType == nsIDOMMutationEvent::MODIFICATION);
|
||||
nsAutoString value;
|
||||
mContent->GetAttr(aNameSpaceID, aAttribute, value);
|
||||
mInputAreaContent->SetAttr(aNameSpaceID, aAttribute, value, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
|
||||
aModType);
|
||||
}
|
||||
|
||||
void
|
||||
nsDateTimeControlFrame::ContentStatesChanged(EventStates aStates)
|
||||
{
|
||||
if (aStates.HasState(NS_EVENT_STATE_DISABLED)) {
|
||||
nsContentUtils::AddScriptRunner(new SyncDisabledStateEvent(this));
|
||||
}
|
||||
}
|
||||
|
||||
nsIAtom*
|
||||
nsDateTimeControlFrame::GetType() const
|
||||
{
|
||||
return nsGkAtoms::dateTimeControlFrame;
|
||||
}
|
||||
119
layout/forms/nsDateTimeControlFrame.h
Normal file
119
layout/forms/nsDateTimeControlFrame.h
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* This frame type is used for input type=date, time, month, week, and
|
||||
* datetime-local.
|
||||
*
|
||||
* NOTE: some of the above-mentioned input types are still to-be-implemented.
|
||||
* See nsCSSFrameConstructor::FindInputData, as well as bug 1286182 (date),
|
||||
* bug 1306215 (month), bug 1306216 (week) and bug 1306217 (datetime-local).
|
||||
*/
|
||||
|
||||
#ifndef nsDateTimeControlFrame_h__
|
||||
#define nsDateTimeControlFrame_h__
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsContainerFrame.h"
|
||||
#include "nsIAnonymousContentCreator.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
struct DateTimeValue;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
class nsDateTimeControlFrame final : public nsContainerFrame,
|
||||
public nsIAnonymousContentCreator
|
||||
{
|
||||
typedef mozilla::dom::DateTimeValue DateTimeValue;
|
||||
|
||||
explicit nsDateTimeControlFrame(nsStyleContext* aContext);
|
||||
|
||||
public:
|
||||
friend nsIFrame* NS_NewDateTimeControlFrame(nsIPresShell* aPresShell,
|
||||
nsStyleContext* aContext);
|
||||
|
||||
void ContentStatesChanged(mozilla::EventStates aStates) override;
|
||||
void DestroyFrom(nsIFrame* aDestructRoot) override;
|
||||
|
||||
NS_DECL_QUERYFRAME_TARGET(nsDateTimeControlFrame)
|
||||
NS_DECL_QUERYFRAME
|
||||
NS_DECL_FRAMEARENA_HELPERS
|
||||
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
nsresult GetFrameName(nsAString& aResult) const override {
|
||||
return MakeFrameName(NS_LITERAL_STRING("DateTimeControl"), aResult);
|
||||
}
|
||||
#endif
|
||||
|
||||
nsIAtom* GetType() const override;
|
||||
|
||||
bool IsFrameOfType(uint32_t aFlags) const override
|
||||
{
|
||||
return nsContainerFrame::IsFrameOfType(aFlags &
|
||||
~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
|
||||
}
|
||||
|
||||
// Reflow
|
||||
nscoord GetMinISize(nsRenderingContext* aRenderingContext) override;
|
||||
|
||||
nscoord GetPrefISize(nsRenderingContext* aRenderingContext) override;
|
||||
|
||||
void Reflow(nsPresContext* aPresContext,
|
||||
ReflowOutput& aDesiredSize,
|
||||
const ReflowInput& aReflowState,
|
||||
nsReflowStatus& aStatus) override;
|
||||
|
||||
// nsIAnonymousContentCreator
|
||||
nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
|
||||
void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
|
||||
uint32_t aFilter) override;
|
||||
|
||||
nsresult AttributeChanged(int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
int32_t aModType) override;
|
||||
|
||||
void UpdateInputBoxValue();
|
||||
void SetValueFromPicker(const DateTimeValue& aValue);
|
||||
void HandleFocusEvent();
|
||||
void HandleBlurEvent();
|
||||
void SetPickerState(bool aOpen);
|
||||
|
||||
private:
|
||||
class SyncDisabledStateEvent;
|
||||
friend class SyncDisabledStateEvent;
|
||||
class SyncDisabledStateEvent : public mozilla::Runnable
|
||||
{
|
||||
public:
|
||||
explicit SyncDisabledStateEvent(nsDateTimeControlFrame* aFrame)
|
||||
: mFrame(aFrame)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
nsDateTimeControlFrame* frame =
|
||||
static_cast<nsDateTimeControlFrame*>(mFrame.GetFrame());
|
||||
NS_ENSURE_STATE(frame);
|
||||
|
||||
frame->SyncDisabledState();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsWeakFrame mFrame;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sync the disabled state of the anonymous children up with our content's.
|
||||
*/
|
||||
void SyncDisabledState();
|
||||
|
||||
// Anonymous child which is bound via XBL to an element that wraps the input
|
||||
// area and reset button.
|
||||
nsCOMPtr<nsIContent> mInputAreaContent;
|
||||
};
|
||||
|
||||
#endif // nsDateTimeControlFrame_h__
|
||||
703
layout/forms/nsFieldSetFrame.cpp
Normal file
703
layout/forms/nsFieldSetFrame.cpp
Normal file
|
|
@ -0,0 +1,703 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsFieldSetFrame.h"
|
||||
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "nsCSSAnonBoxes.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsLegendFrame.h"
|
||||
#include "nsCSSRendering.h"
|
||||
#include <algorithm>
|
||||
#include "nsIFrame.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "mozilla/RestyleManager.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "nsRenderingContext.h"
|
||||
#include "nsIScrollableFrame.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::image;
|
||||
using namespace mozilla::layout;
|
||||
|
||||
nsContainerFrame*
|
||||
NS_NewFieldSetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
|
||||
{
|
||||
return new (aPresShell) nsFieldSetFrame(aContext);
|
||||
}
|
||||
|
||||
NS_IMPL_FRAMEARENA_HELPERS(nsFieldSetFrame)
|
||||
|
||||
nsFieldSetFrame::nsFieldSetFrame(nsStyleContext* aContext)
|
||||
: nsContainerFrame(aContext)
|
||||
, mLegendRect(GetWritingMode())
|
||||
{
|
||||
mLegendSpace = 0;
|
||||
}
|
||||
|
||||
nsIAtom*
|
||||
nsFieldSetFrame::GetType() const
|
||||
{
|
||||
return nsGkAtoms::fieldSetFrame;
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsFieldSetFrame::VisualBorderRectRelativeToSelf() const
|
||||
{
|
||||
WritingMode wm = GetWritingMode();
|
||||
css::Side legendSide = wm.PhysicalSide(eLogicalSideBStart);
|
||||
nscoord legendBorder = StyleBorder()->GetComputedBorderWidth(legendSide);
|
||||
LogicalRect r(wm, LogicalPoint(wm, 0, 0), GetLogicalSize(wm));
|
||||
nsSize containerSize = r.Size(wm).GetPhysicalSize(wm);
|
||||
if (legendBorder < mLegendRect.BSize(wm)) {
|
||||
nscoord off = (mLegendRect.BSize(wm) - legendBorder) / 2;
|
||||
r.BStart(wm) += off;
|
||||
r.BSize(wm) -= off;
|
||||
}
|
||||
return r.GetPhysicalRect(wm, containerSize);
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsFieldSetFrame::GetInner() const
|
||||
{
|
||||
nsIFrame* last = mFrames.LastChild();
|
||||
if (last &&
|
||||
last->StyleContext()->GetPseudo() == nsCSSAnonBoxes::fieldsetContent) {
|
||||
return last;
|
||||
}
|
||||
MOZ_ASSERT(mFrames.LastChild() == mFrames.FirstChild());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsFieldSetFrame::GetLegend() const
|
||||
{
|
||||
if (mFrames.FirstChild() == GetInner()) {
|
||||
MOZ_ASSERT(mFrames.LastChild() == mFrames.FirstChild());
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(mFrames.FirstChild() &&
|
||||
mFrames.FirstChild()->GetContentInsertionFrame()->GetType() ==
|
||||
nsGkAtoms::legendFrame);
|
||||
return mFrames.FirstChild();
|
||||
}
|
||||
|
||||
class nsDisplayFieldSetBorderBackground : public nsDisplayItem {
|
||||
public:
|
||||
nsDisplayFieldSetBorderBackground(nsDisplayListBuilder* aBuilder,
|
||||
nsFieldSetFrame* aFrame)
|
||||
: nsDisplayItem(aBuilder, aFrame) {
|
||||
MOZ_COUNT_CTOR(nsDisplayFieldSetBorderBackground);
|
||||
}
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
virtual ~nsDisplayFieldSetBorderBackground() {
|
||||
MOZ_COUNT_DTOR(nsDisplayFieldSetBorderBackground);
|
||||
}
|
||||
#endif
|
||||
virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
|
||||
HitTestState* aState,
|
||||
nsTArray<nsIFrame*> *aOutFrames) override;
|
||||
virtual void Paint(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext* aCtx) override;
|
||||
virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override;
|
||||
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
|
||||
const nsDisplayItemGeometry* aGeometry,
|
||||
nsRegion *aInvalidRegion) override;
|
||||
NS_DISPLAY_DECL_NAME("FieldSetBorderBackground", TYPE_FIELDSET_BORDER_BACKGROUND)
|
||||
};
|
||||
|
||||
void nsDisplayFieldSetBorderBackground::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
|
||||
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
|
||||
{
|
||||
// aPt is guaranteed to be in this item's bounds. We do the hit test based on the
|
||||
// frame bounds even though our background doesn't cover the whole frame.
|
||||
// It's not clear whether this is correct.
|
||||
aOutFrames->AppendElement(mFrame);
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayFieldSetBorderBackground::Paint(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext* aCtx)
|
||||
{
|
||||
DrawResult result = static_cast<nsFieldSetFrame*>(mFrame)->
|
||||
PaintBorder(aBuilder, *aCtx, ToReferenceFrame(), mVisibleRect);
|
||||
|
||||
nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
|
||||
}
|
||||
|
||||
nsDisplayItemGeometry*
|
||||
nsDisplayFieldSetBorderBackground::AllocateGeometry(nsDisplayListBuilder* aBuilder)
|
||||
{
|
||||
return new nsDisplayItemGenericImageGeometry(this, aBuilder);
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayFieldSetBorderBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
|
||||
const nsDisplayItemGeometry* aGeometry,
|
||||
nsRegion *aInvalidRegion)
|
||||
{
|
||||
auto geometry =
|
||||
static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
|
||||
|
||||
if (aBuilder->ShouldSyncDecodeImages() &&
|
||||
geometry->ShouldInvalidateToSyncDecodeImages()) {
|
||||
bool snap;
|
||||
aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
|
||||
}
|
||||
|
||||
nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
|
||||
}
|
||||
|
||||
void
|
||||
nsFieldSetFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists) {
|
||||
// Paint our background and border in a special way.
|
||||
// REVIEW: We don't really need to check frame emptiness here; if it's empty,
|
||||
// the background/border display item won't do anything, and if it isn't empty,
|
||||
// we need to paint the outline
|
||||
if (!(GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) &&
|
||||
IsVisibleForPainting(aBuilder)) {
|
||||
if (StyleEffects()->mBoxShadow) {
|
||||
aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
|
||||
nsDisplayBoxShadowOuter(aBuilder, this));
|
||||
}
|
||||
|
||||
nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
|
||||
aBuilder, this, VisualBorderRectRelativeToSelf(),
|
||||
aLists.BorderBackground(),
|
||||
/* aAllowWillPaintBorderOptimization = */ false);
|
||||
|
||||
aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
|
||||
nsDisplayFieldSetBorderBackground(aBuilder, this));
|
||||
|
||||
DisplayOutlineUnconditional(aBuilder, aLists);
|
||||
|
||||
DO_GLOBAL_REFLOW_COUNT_DSP("nsFieldSetFrame");
|
||||
}
|
||||
|
||||
if (GetPrevInFlow()) {
|
||||
DisplayOverflowContainers(aBuilder, aDirtyRect, aLists);
|
||||
}
|
||||
|
||||
nsDisplayListCollection contentDisplayItems;
|
||||
if (nsIFrame* inner = GetInner()) {
|
||||
// Collect the inner frame's display items into their own collection.
|
||||
// We need to be calling BuildDisplayList on it before the legend in
|
||||
// case it contains out-of-flow frames whose placeholders are in the
|
||||
// legend. However, we want the inner frame's display items to be
|
||||
// after the legend's display items in z-order, so we need to save them
|
||||
// and append them later.
|
||||
BuildDisplayListForChild(aBuilder, inner, aDirtyRect, contentDisplayItems);
|
||||
}
|
||||
if (nsIFrame* legend = GetLegend()) {
|
||||
// The legend's background goes on our BlockBorderBackgrounds list because
|
||||
// it's a block child.
|
||||
nsDisplayListSet set(aLists, aLists.BlockBorderBackgrounds());
|
||||
BuildDisplayListForChild(aBuilder, legend, aDirtyRect, set);
|
||||
}
|
||||
// Put the inner frame's display items on the master list. Note that this
|
||||
// moves its border/background display items to our BorderBackground() list,
|
||||
// which isn't really correct, but it's OK because the inner frame is
|
||||
// anonymous and can't have its own border and background.
|
||||
contentDisplayItems.MoveTo(aLists);
|
||||
}
|
||||
|
||||
DrawResult
|
||||
nsFieldSetFrame::PaintBorder(
|
||||
nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext& aRenderingContext,
|
||||
nsPoint aPt,
|
||||
const nsRect& aDirtyRect)
|
||||
{
|
||||
// if the border is smaller than the legend. Move the border down
|
||||
// to be centered on the legend.
|
||||
// FIXME: This means border-radius clamping is incorrect; we should
|
||||
// override nsIFrame::GetBorderRadii.
|
||||
WritingMode wm = GetWritingMode();
|
||||
nsRect rect = VisualBorderRectRelativeToSelf();
|
||||
nscoord off = wm.IsVertical() ? rect.x : rect.y;
|
||||
rect += aPt;
|
||||
nsPresContext* presContext = PresContext();
|
||||
|
||||
PaintBorderFlags borderFlags = aBuilder->ShouldSyncDecodeImages()
|
||||
? PaintBorderFlags::SYNC_DECODE_IMAGES
|
||||
: PaintBorderFlags();
|
||||
|
||||
DrawResult result = DrawResult::SUCCESS;
|
||||
|
||||
nsCSSRendering::PaintBoxShadowInner(presContext, aRenderingContext,
|
||||
this, rect);
|
||||
|
||||
if (nsIFrame* legend = GetLegend()) {
|
||||
css::Side legendSide = wm.PhysicalSide(eLogicalSideBStart);
|
||||
nscoord legendBorderWidth =
|
||||
StyleBorder()->GetComputedBorderWidth(legendSide);
|
||||
|
||||
// Use the rect of the legend frame, not mLegendRect, so we draw our
|
||||
// border under the legend's inline-start and -end margins.
|
||||
LogicalRect legendRect(wm, legend->GetRect() + aPt, rect.Size());
|
||||
|
||||
// Compute clipRect using logical coordinates, so that the legend space
|
||||
// will be clipped out of the appropriate physical side depending on mode.
|
||||
LogicalRect clipRect = LogicalRect(wm, rect, rect.Size());
|
||||
DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
|
||||
gfxContext* gfx = aRenderingContext.ThebesContext();
|
||||
int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
|
||||
|
||||
// draw inline-start portion of the block-start side of the border
|
||||
clipRect.ISize(wm) = legendRect.IStart(wm) - clipRect.IStart(wm);
|
||||
clipRect.BSize(wm) = legendBorderWidth;
|
||||
|
||||
gfx->Save();
|
||||
gfx->Clip(NSRectToSnappedRect(clipRect.GetPhysicalRect(wm, rect.Size()),
|
||||
appUnitsPerDevPixel, *drawTarget));
|
||||
result &=
|
||||
nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
|
||||
aDirtyRect, rect, mStyleContext, borderFlags);
|
||||
gfx->Restore();
|
||||
|
||||
// draw inline-end portion of the block-start side of the border
|
||||
clipRect = LogicalRect(wm, rect, rect.Size());
|
||||
clipRect.ISize(wm) = clipRect.IEnd(wm) - legendRect.IEnd(wm);
|
||||
clipRect.IStart(wm) = legendRect.IEnd(wm);
|
||||
clipRect.BSize(wm) = legendBorderWidth;
|
||||
|
||||
gfx->Save();
|
||||
gfx->Clip(NSRectToSnappedRect(clipRect.GetPhysicalRect(wm, rect.Size()),
|
||||
appUnitsPerDevPixel, *drawTarget));
|
||||
result &=
|
||||
nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
|
||||
aDirtyRect, rect, mStyleContext, borderFlags);
|
||||
gfx->Restore();
|
||||
|
||||
// draw remainder of the border (omitting the block-start side)
|
||||
clipRect = LogicalRect(wm, rect, rect.Size());
|
||||
clipRect.BStart(wm) += legendBorderWidth;
|
||||
clipRect.BSize(wm) = BSize(wm) - (off + legendBorderWidth);
|
||||
|
||||
gfx->Save();
|
||||
gfx->Clip(NSRectToSnappedRect(clipRect.GetPhysicalRect(wm, rect.Size()),
|
||||
appUnitsPerDevPixel, *drawTarget));
|
||||
result &=
|
||||
nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
|
||||
aDirtyRect, rect, mStyleContext, borderFlags);
|
||||
gfx->Restore();
|
||||
} else {
|
||||
result &=
|
||||
nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
|
||||
aDirtyRect, nsRect(aPt, mRect.Size()),
|
||||
mStyleContext, borderFlags);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFieldSetFrame::GetIntrinsicISize(nsRenderingContext* aRenderingContext,
|
||||
nsLayoutUtils::IntrinsicISizeType aType)
|
||||
{
|
||||
nscoord legendWidth = 0;
|
||||
nscoord contentWidth = 0;
|
||||
if (nsIFrame* legend = GetLegend()) {
|
||||
legendWidth =
|
||||
nsLayoutUtils::IntrinsicForContainer(aRenderingContext, legend, aType);
|
||||
}
|
||||
|
||||
if (nsIFrame* inner = GetInner()) {
|
||||
// Ignore padding on the inner, since the padding will be applied to the
|
||||
// outer instead, and the padding computed for the inner is wrong
|
||||
// for percentage padding.
|
||||
contentWidth =
|
||||
nsLayoutUtils::IntrinsicForContainer(aRenderingContext, inner, aType,
|
||||
nsLayoutUtils::IGNORE_PADDING);
|
||||
}
|
||||
|
||||
return std::max(legendWidth, contentWidth);
|
||||
}
|
||||
|
||||
|
||||
nscoord
|
||||
nsFieldSetFrame::GetMinISize(nsRenderingContext* aRenderingContext)
|
||||
{
|
||||
nscoord result = 0;
|
||||
DISPLAY_MIN_WIDTH(this, result);
|
||||
|
||||
result = GetIntrinsicISize(aRenderingContext, nsLayoutUtils::MIN_ISIZE);
|
||||
return result;
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFieldSetFrame::GetPrefISize(nsRenderingContext* aRenderingContext)
|
||||
{
|
||||
nscoord result = 0;
|
||||
DISPLAY_PREF_WIDTH(this, result);
|
||||
|
||||
result = GetIntrinsicISize(aRenderingContext, nsLayoutUtils::PREF_ISIZE);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* virtual */
|
||||
LogicalSize
|
||||
nsFieldSetFrame::ComputeSize(nsRenderingContext *aRenderingContext,
|
||||
WritingMode aWM,
|
||||
const LogicalSize& aCBSize,
|
||||
nscoord aAvailableISize,
|
||||
const LogicalSize& aMargin,
|
||||
const LogicalSize& aBorder,
|
||||
const LogicalSize& aPadding,
|
||||
ComputeSizeFlags aFlags)
|
||||
{
|
||||
LogicalSize result =
|
||||
nsContainerFrame::ComputeSize(aRenderingContext, aWM,
|
||||
aCBSize, aAvailableISize,
|
||||
aMargin, aBorder, aPadding, aFlags);
|
||||
|
||||
// XXX The code below doesn't make sense if the caller's writing mode
|
||||
// is orthogonal to this frame's. Not sure yet what should happen then;
|
||||
// for now, just bail out.
|
||||
if (aWM.IsVertical() != GetWritingMode().IsVertical()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Fieldsets never shrink below their min width.
|
||||
|
||||
// If we're a container for font size inflation, then shrink
|
||||
// wrapping inside of us should not apply font size inflation.
|
||||
AutoMaybeDisableFontInflation an(this);
|
||||
|
||||
nscoord minISize = GetMinISize(aRenderingContext);
|
||||
if (minISize > result.ISize(aWM)) {
|
||||
result.ISize(aWM) = minISize;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
|
||||
ReflowOutput& aDesiredSize,
|
||||
const ReflowInput& aReflowInput,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
MarkInReflow();
|
||||
DO_GLOBAL_REFLOW_COUNT("nsFieldSetFrame");
|
||||
DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
|
||||
|
||||
NS_PRECONDITION(aReflowInput.ComputedISize() != NS_INTRINSICSIZE,
|
||||
"Should have a precomputed inline-size!");
|
||||
|
||||
// Initialize OUT parameter
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
|
||||
nsOverflowAreas ocBounds;
|
||||
nsReflowStatus ocStatus = NS_FRAME_COMPLETE;
|
||||
if (GetPrevInFlow()) {
|
||||
ReflowOverflowContainerChildren(aPresContext, aReflowInput, ocBounds, 0,
|
||||
ocStatus);
|
||||
}
|
||||
|
||||
//------------ Handle Incremental Reflow -----------------
|
||||
bool reflowInner;
|
||||
bool reflowLegend;
|
||||
nsIFrame* legend = GetLegend();
|
||||
nsIFrame* inner = GetInner();
|
||||
if (aReflowInput.ShouldReflowAllKids()) {
|
||||
reflowInner = inner != nullptr;
|
||||
reflowLegend = legend != nullptr;
|
||||
} else {
|
||||
reflowInner = inner && NS_SUBTREE_DIRTY(inner);
|
||||
reflowLegend = legend && NS_SUBTREE_DIRTY(legend);
|
||||
}
|
||||
|
||||
// We don't allow fieldsets to break vertically. If we did, we'd
|
||||
// need logic here to push and pull overflow frames.
|
||||
// Since we're not applying our padding in this frame, we need to add it here
|
||||
// to compute the available width for our children.
|
||||
WritingMode wm = GetWritingMode();
|
||||
WritingMode innerWM = inner ? inner->GetWritingMode() : wm;
|
||||
WritingMode legendWM = legend ? legend->GetWritingMode() : wm;
|
||||
LogicalSize innerAvailSize = aReflowInput.ComputedSizeWithPadding(innerWM);
|
||||
LogicalSize legendAvailSize = aReflowInput.ComputedSizeWithPadding(legendWM);
|
||||
innerAvailSize.BSize(innerWM) = legendAvailSize.BSize(legendWM) =
|
||||
NS_UNCONSTRAINEDSIZE;
|
||||
NS_ASSERTION(!inner ||
|
||||
nsLayoutUtils::IntrinsicForContainer(aReflowInput.mRenderingContext,
|
||||
inner,
|
||||
nsLayoutUtils::MIN_ISIZE) <=
|
||||
innerAvailSize.ISize(innerWM),
|
||||
"Bogus availSize.ISize; should be bigger");
|
||||
NS_ASSERTION(!legend ||
|
||||
nsLayoutUtils::IntrinsicForContainer(aReflowInput.mRenderingContext,
|
||||
legend,
|
||||
nsLayoutUtils::MIN_ISIZE) <=
|
||||
legendAvailSize.ISize(legendWM),
|
||||
"Bogus availSize.ISize; should be bigger");
|
||||
|
||||
// get our border and padding
|
||||
LogicalMargin border = aReflowInput.ComputedLogicalBorderPadding() -
|
||||
aReflowInput.ComputedLogicalPadding();
|
||||
|
||||
// Figure out how big the legend is if there is one.
|
||||
// get the legend's margin
|
||||
LogicalMargin legendMargin(wm);
|
||||
// reflow the legend only if needed
|
||||
Maybe<ReflowInput> legendReflowInput;
|
||||
if (legend) {
|
||||
legendReflowInput.emplace(aPresContext, aReflowInput, legend,
|
||||
legendAvailSize);
|
||||
}
|
||||
if (reflowLegend) {
|
||||
ReflowOutput legendDesiredSize(aReflowInput);
|
||||
|
||||
// We'll move the legend to its proper place later, so the position
|
||||
// and containerSize passed here are unimportant.
|
||||
const nsSize dummyContainerSize;
|
||||
ReflowChild(legend, aPresContext, legendDesiredSize, *legendReflowInput,
|
||||
wm, LogicalPoint(wm), dummyContainerSize,
|
||||
NS_FRAME_NO_MOVE_FRAME, aStatus);
|
||||
#ifdef NOISY_REFLOW
|
||||
printf(" returned (%d, %d)\n",
|
||||
legendDesiredSize.Width(), legendDesiredSize.Height());
|
||||
#endif
|
||||
// figure out the legend's rectangle
|
||||
legendMargin = legend->GetLogicalUsedMargin(wm);
|
||||
mLegendRect =
|
||||
LogicalRect(wm, 0, 0,
|
||||
legendDesiredSize.ISize(wm) + legendMargin.IStartEnd(wm),
|
||||
legendDesiredSize.BSize(wm) + legendMargin.BStartEnd(wm));
|
||||
nscoord oldSpace = mLegendSpace;
|
||||
mLegendSpace = 0;
|
||||
if (mLegendRect.BSize(wm) > border.BStart(wm)) {
|
||||
// center the border on the legend
|
||||
mLegendSpace = mLegendRect.BSize(wm) - border.BStart(wm);
|
||||
} else {
|
||||
mLegendRect.BStart(wm) =
|
||||
(border.BStart(wm) - mLegendRect.BSize(wm)) / 2;
|
||||
}
|
||||
|
||||
// if the legend space changes then we need to reflow the
|
||||
// content area as well.
|
||||
if (mLegendSpace != oldSpace && inner) {
|
||||
reflowInner = true;
|
||||
}
|
||||
|
||||
FinishReflowChild(legend, aPresContext, legendDesiredSize,
|
||||
legendReflowInput.ptr(), wm, LogicalPoint(wm),
|
||||
dummyContainerSize, NS_FRAME_NO_MOVE_FRAME);
|
||||
} else if (!legend) {
|
||||
mLegendRect.SetEmpty();
|
||||
mLegendSpace = 0;
|
||||
} else {
|
||||
// mLegendSpace and mLegendRect haven't changed, but we need
|
||||
// the used margin when placing the legend.
|
||||
legendMargin = legend->GetLogicalUsedMargin(wm);
|
||||
}
|
||||
|
||||
// This containerSize is incomplete as yet: it does not include the size
|
||||
// of the |inner| frame itself.
|
||||
nsSize containerSize = (LogicalSize(wm, 0, mLegendSpace) +
|
||||
border.Size(wm)).GetPhysicalSize(wm);
|
||||
// reflow the content frame only if needed
|
||||
if (reflowInner) {
|
||||
ReflowInput kidReflowInput(aPresContext, aReflowInput, inner,
|
||||
innerAvailSize, nullptr,
|
||||
ReflowInput::CALLER_WILL_INIT);
|
||||
// Override computed padding, in case it's percentage padding
|
||||
kidReflowInput.Init(aPresContext, nullptr, nullptr,
|
||||
&aReflowInput.ComputedPhysicalPadding());
|
||||
// Our child is "height:100%" but we actually want its height to be reduced
|
||||
// by the amount of content-height the legend is eating up, unless our
|
||||
// height is unconstrained (in which case the child's will be too).
|
||||
if (aReflowInput.ComputedBSize() != NS_UNCONSTRAINEDSIZE) {
|
||||
kidReflowInput.SetComputedBSize(
|
||||
std::max(0, aReflowInput.ComputedBSize() - mLegendSpace));
|
||||
}
|
||||
|
||||
if (aReflowInput.ComputedMinBSize() > 0) {
|
||||
kidReflowInput.ComputedMinBSize() =
|
||||
std::max(0, aReflowInput.ComputedMinBSize() - mLegendSpace);
|
||||
}
|
||||
|
||||
if (aReflowInput.ComputedMaxBSize() != NS_UNCONSTRAINEDSIZE) {
|
||||
kidReflowInput.ComputedMaxBSize() =
|
||||
std::max(0, aReflowInput.ComputedMaxBSize() - mLegendSpace);
|
||||
}
|
||||
|
||||
ReflowOutput kidDesiredSize(kidReflowInput,
|
||||
aDesiredSize.mFlags);
|
||||
// Reflow the frame
|
||||
NS_ASSERTION(kidReflowInput.ComputedPhysicalMargin() == nsMargin(0,0,0,0),
|
||||
"Margins on anonymous fieldset child not supported!");
|
||||
LogicalPoint pt(wm, border.IStart(wm), border.BStart(wm) + mLegendSpace);
|
||||
|
||||
// We don't know the correct containerSize until we have reflowed |inner|,
|
||||
// so we use a dummy value for now; FinishReflowChild will fix the position
|
||||
// if necessary.
|
||||
const nsSize dummyContainerSize;
|
||||
ReflowChild(inner, aPresContext, kidDesiredSize, kidReflowInput,
|
||||
wm, pt, dummyContainerSize, 0, aStatus);
|
||||
|
||||
// Update containerSize to account for size of the inner frame, so that
|
||||
// FinishReflowChild can position it correctly.
|
||||
containerSize += kidDesiredSize.PhysicalSize();
|
||||
FinishReflowChild(inner, aPresContext, kidDesiredSize,
|
||||
&kidReflowInput, wm, pt, containerSize, 0);
|
||||
NS_FRAME_TRACE_REFLOW_OUT("FieldSet::Reflow", aStatus);
|
||||
} else if (inner) {
|
||||
// |inner| didn't need to be reflowed but we do need to include its size
|
||||
// in containerSize.
|
||||
containerSize += inner->GetSize();
|
||||
}
|
||||
|
||||
LogicalRect contentRect(wm);
|
||||
if (inner) {
|
||||
// We don't support margins on inner, so our content rect is just the
|
||||
// inner's border-box. (We don't really care about container size at this
|
||||
// point, as we'll figure out the actual positioning later.)
|
||||
contentRect = inner->GetLogicalRect(wm, containerSize);
|
||||
}
|
||||
|
||||
// Our content rect must fill up the available width
|
||||
LogicalSize availSize = aReflowInput.ComputedSizeWithPadding(wm);
|
||||
if (availSize.ISize(wm) > contentRect.ISize(wm)) {
|
||||
contentRect.ISize(wm) = innerAvailSize.ISize(wm);
|
||||
}
|
||||
|
||||
if (legend) {
|
||||
// The legend is positioned inline-wards within the inner's content rect
|
||||
// (so that padding on the fieldset affects the legend position).
|
||||
LogicalRect innerContentRect = contentRect;
|
||||
innerContentRect.Deflate(wm, aReflowInput.ComputedLogicalPadding());
|
||||
// If the inner content rect is larger than the legend, we can align the
|
||||
// legend.
|
||||
if (innerContentRect.ISize(wm) > mLegendRect.ISize(wm)) {
|
||||
// NOTE legend @align values are: left/right/center/top/bottom.
|
||||
// GetLogicalAlign converts left/right to start/end for the given WM.
|
||||
// @see HTMLLegendElement::ParseAttribute, nsLegendFrame::GetLogicalAlign
|
||||
int32_t align = static_cast<nsLegendFrame*>
|
||||
(legend->GetContentInsertionFrame())->GetLogicalAlign(wm);
|
||||
switch (align) {
|
||||
case NS_STYLE_TEXT_ALIGN_END:
|
||||
mLegendRect.IStart(wm) =
|
||||
innerContentRect.IEnd(wm) - mLegendRect.ISize(wm);
|
||||
break;
|
||||
case NS_STYLE_TEXT_ALIGN_CENTER:
|
||||
// Note: rounding removed; there doesn't seem to be any need
|
||||
mLegendRect.IStart(wm) = innerContentRect.IStart(wm) +
|
||||
(innerContentRect.ISize(wm) - mLegendRect.ISize(wm)) / 2;
|
||||
break;
|
||||
case NS_STYLE_TEXT_ALIGN_START:
|
||||
case NS_STYLE_VERTICAL_ALIGN_TOP:
|
||||
case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
|
||||
mLegendRect.IStart(wm) = innerContentRect.IStart(wm);
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("unexpected GetLogicalAlign value");
|
||||
}
|
||||
} else {
|
||||
// otherwise make place for the legend
|
||||
mLegendRect.IStart(wm) = innerContentRect.IStart(wm);
|
||||
innerContentRect.ISize(wm) = mLegendRect.ISize(wm);
|
||||
contentRect.ISize(wm) = mLegendRect.ISize(wm) +
|
||||
aReflowInput.ComputedLogicalPadding().IStartEnd(wm);
|
||||
}
|
||||
|
||||
// place the legend
|
||||
LogicalRect actualLegendRect = mLegendRect;
|
||||
actualLegendRect.Deflate(wm, legendMargin);
|
||||
LogicalPoint actualLegendPos(actualLegendRect.Origin(wm));
|
||||
|
||||
// Note that legend's writing mode may be different from the fieldset's,
|
||||
// so we need to convert offsets before applying them to it (bug 1134534).
|
||||
LogicalMargin offsets =
|
||||
legendReflowInput->ComputedLogicalOffsets().
|
||||
ConvertTo(wm, legendReflowInput->GetWritingMode());
|
||||
ReflowInput::ApplyRelativePositioning(legend, wm, offsets,
|
||||
&actualLegendPos,
|
||||
containerSize);
|
||||
|
||||
legend->SetPosition(wm, actualLegendPos, containerSize);
|
||||
nsContainerFrame::PositionFrameView(legend);
|
||||
nsContainerFrame::PositionChildViews(legend);
|
||||
}
|
||||
|
||||
// Return our size and our result.
|
||||
LogicalSize finalSize(wm, contentRect.ISize(wm) + border.IStartEnd(wm),
|
||||
mLegendSpace + border.BStartEnd(wm) +
|
||||
(inner ? inner->BSize(wm) : 0));
|
||||
aDesiredSize.SetSize(wm, finalSize);
|
||||
aDesiredSize.SetOverflowAreasToDesiredBounds();
|
||||
|
||||
if (legend) {
|
||||
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, legend);
|
||||
}
|
||||
if (inner) {
|
||||
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, inner);
|
||||
}
|
||||
|
||||
// Merge overflow container bounds and status.
|
||||
aDesiredSize.mOverflowAreas.UnionWith(ocBounds);
|
||||
NS_MergeReflowStatusInto(&aStatus, ocStatus);
|
||||
|
||||
FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowInput, aStatus);
|
||||
|
||||
InvalidateFrame();
|
||||
|
||||
NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
nsFieldSetFrame::SetInitialChildList(ChildListID aListID,
|
||||
nsFrameList& aChildList)
|
||||
{
|
||||
nsContainerFrame::SetInitialChildList(aListID, aChildList);
|
||||
MOZ_ASSERT(aListID != kPrincipalList || GetInner(),
|
||||
"Setting principal child list should populate our inner frame");
|
||||
}
|
||||
void
|
||||
nsFieldSetFrame::AppendFrames(ChildListID aListID,
|
||||
nsFrameList& aFrameList)
|
||||
{
|
||||
MOZ_CRASH("nsFieldSetFrame::AppendFrames not supported");
|
||||
}
|
||||
|
||||
void
|
||||
nsFieldSetFrame::InsertFrames(ChildListID aListID,
|
||||
nsIFrame* aPrevFrame,
|
||||
nsFrameList& aFrameList)
|
||||
{
|
||||
MOZ_CRASH("nsFieldSetFrame::InsertFrames not supported");
|
||||
}
|
||||
|
||||
void
|
||||
nsFieldSetFrame::RemoveFrame(ChildListID aListID,
|
||||
nsIFrame* aOldFrame)
|
||||
{
|
||||
MOZ_CRASH("nsFieldSetFrame::RemoveFrame not supported");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
a11y::AccType
|
||||
nsFieldSetFrame::AccessibleType()
|
||||
{
|
||||
return a11y::eHTMLGroupboxType;
|
||||
}
|
||||
#endif
|
||||
|
||||
nscoord
|
||||
nsFieldSetFrame::GetLogicalBaseline(WritingMode aWritingMode) const
|
||||
{
|
||||
nsIFrame* inner = GetInner();
|
||||
return inner->BStart(aWritingMode, GetParent()->GetSize()) +
|
||||
inner->GetLogicalBaseline(aWritingMode);
|
||||
}
|
||||
110
layout/forms/nsFieldSetFrame.h
Normal file
110
layout/forms/nsFieldSetFrame.h
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsFieldSetFrame_h___
|
||||
#define nsFieldSetFrame_h___
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "imgIContainer.h"
|
||||
#include "nsContainerFrame.h"
|
||||
|
||||
class nsFieldSetFrame final : public nsContainerFrame
|
||||
{
|
||||
typedef mozilla::image::DrawResult DrawResult;
|
||||
|
||||
public:
|
||||
NS_DECL_FRAMEARENA_HELPERS
|
||||
|
||||
explicit nsFieldSetFrame(nsStyleContext* aContext);
|
||||
|
||||
nscoord
|
||||
GetIntrinsicISize(nsRenderingContext* aRenderingContext,
|
||||
nsLayoutUtils::IntrinsicISizeType);
|
||||
virtual nscoord GetMinISize(nsRenderingContext* aRenderingContext) override;
|
||||
virtual nscoord GetPrefISize(nsRenderingContext* aRenderingContext) override;
|
||||
virtual mozilla::LogicalSize
|
||||
ComputeSize(nsRenderingContext *aRenderingContext,
|
||||
mozilla::WritingMode aWritingMode,
|
||||
const mozilla::LogicalSize& aCBSize,
|
||||
nscoord aAvailableISize,
|
||||
const mozilla::LogicalSize& aMargin,
|
||||
const mozilla::LogicalSize& aBorder,
|
||||
const mozilla::LogicalSize& aPadding,
|
||||
ComputeSizeFlags aFlags) override;
|
||||
virtual nscoord GetLogicalBaseline(mozilla::WritingMode aWritingMode) const override;
|
||||
|
||||
/**
|
||||
* The area to paint box-shadows around. It's the border rect except
|
||||
* when there's a <legend> we offset the y-position to the center of it.
|
||||
*/
|
||||
virtual nsRect VisualBorderRectRelativeToSelf() const override;
|
||||
|
||||
virtual void Reflow(nsPresContext* aPresContext,
|
||||
ReflowOutput& aDesiredSize,
|
||||
const ReflowInput& aReflowInput,
|
||||
nsReflowStatus& aStatus) override;
|
||||
|
||||
virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists) override;
|
||||
|
||||
DrawResult PaintBorder(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext& aRenderingContext,
|
||||
nsPoint aPt, const nsRect& aDirtyRect);
|
||||
|
||||
#ifdef DEBUG
|
||||
virtual void SetInitialChildList(ChildListID aListID,
|
||||
nsFrameList& aChildList) override;
|
||||
virtual void AppendFrames(ChildListID aListID,
|
||||
nsFrameList& aFrameList) override;
|
||||
virtual void InsertFrames(ChildListID aListID,
|
||||
nsIFrame* aPrevFrame,
|
||||
nsFrameList& aFrameList) override;
|
||||
virtual void RemoveFrame(ChildListID aListID,
|
||||
nsIFrame* aOldFrame) override;
|
||||
#endif
|
||||
|
||||
virtual nsIAtom* GetType() const override;
|
||||
virtual bool IsFrameOfType(uint32_t aFlags) const override
|
||||
{
|
||||
return nsContainerFrame::IsFrameOfType(aFlags &
|
||||
~nsIFrame::eCanContainOverflowContainers);
|
||||
}
|
||||
virtual nsIScrollableFrame* GetScrollTargetFrame() override
|
||||
{
|
||||
return do_QueryFrame(GetInner());
|
||||
}
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
virtual mozilla::a11y::AccType AccessibleType() override;
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
virtual nsresult GetFrameName(nsAString& aResult) const override {
|
||||
return MakeFrameName(NS_LITERAL_STRING("FieldSet"), aResult);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Return the anonymous frame that contains all descendants except
|
||||
* the legend frame. This is currently always a block frame with
|
||||
* pseudo nsCSSAnonBoxes::fieldsetContent -- this may change in the
|
||||
* future when we add support for CSS overflow for <fieldset>.
|
||||
*/
|
||||
nsIFrame* GetInner() const;
|
||||
|
||||
/**
|
||||
* Return the frame that represents the legend if any. This may be
|
||||
* a nsLegendFrame or a nsHTMLScrollFrame with the nsLegendFrame as the
|
||||
* scrolled frame (aka content insertion frame).
|
||||
*/
|
||||
nsIFrame* GetLegend() const;
|
||||
|
||||
protected:
|
||||
mozilla::LogicalRect mLegendRect;
|
||||
nscoord mLegendSpace;
|
||||
};
|
||||
|
||||
#endif // nsFieldSetFrame_h___
|
||||
506
layout/forms/nsFileControlFrame.cpp
Normal file
506
layout/forms/nsFileControlFrame.cpp
Normal file
|
|
@ -0,0 +1,506 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsFileControlFrame.h"
|
||||
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "mozilla/dom/NodeInfo.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/DataTransfer.h"
|
||||
#include "mozilla/dom/HTMLButtonElement.h"
|
||||
#include "mozilla/dom/HTMLInputElement.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsNodeInfoManager.h"
|
||||
#include "nsContentCreatorFunctions.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/dom/DOMStringList.h"
|
||||
#include "mozilla/dom/Directory.h"
|
||||
#include "mozilla/dom/FileList.h"
|
||||
#include "nsIDOMDragEvent.h"
|
||||
#include "nsIDOMFileList.h"
|
||||
#include "nsContentList.h"
|
||||
#include "nsIDOMMutationEvent.h"
|
||||
#include "nsTextNode.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
nsIFrame*
|
||||
NS_NewFileControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
|
||||
{
|
||||
return new (aPresShell) nsFileControlFrame(aContext);
|
||||
}
|
||||
|
||||
NS_IMPL_FRAMEARENA_HELPERS(nsFileControlFrame)
|
||||
|
||||
nsFileControlFrame::nsFileControlFrame(nsStyleContext* aContext)
|
||||
: nsBlockFrame(aContext)
|
||||
{
|
||||
AddStateBits(NS_BLOCK_FLOAT_MGR);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsFileControlFrame::Init(nsIContent* aContent,
|
||||
nsContainerFrame* aParent,
|
||||
nsIFrame* aPrevInFlow)
|
||||
{
|
||||
nsBlockFrame::Init(aContent, aParent, aPrevInFlow);
|
||||
|
||||
mMouseListener = new DnDListener(this);
|
||||
}
|
||||
|
||||
void
|
||||
nsFileControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
|
||||
{
|
||||
ENSURE_TRUE(mContent);
|
||||
|
||||
// Remove the events.
|
||||
if (mContent) {
|
||||
mContent->RemoveSystemEventListener(NS_LITERAL_STRING("drop"),
|
||||
mMouseListener, false);
|
||||
mContent->RemoveSystemEventListener(NS_LITERAL_STRING("dragover"),
|
||||
mMouseListener, false);
|
||||
}
|
||||
|
||||
nsContentUtils::DestroyAnonymousContent(&mTextContent);
|
||||
nsContentUtils::DestroyAnonymousContent(&mBrowseFilesOrDirs);
|
||||
|
||||
mMouseListener->ForgetFrame();
|
||||
nsBlockFrame::DestroyFrom(aDestructRoot);
|
||||
}
|
||||
|
||||
static already_AddRefed<Element>
|
||||
MakeAnonButton(nsIDocument* aDoc, const char* labelKey,
|
||||
HTMLInputElement* aInputElement,
|
||||
const nsAString& aAccessKey)
|
||||
{
|
||||
RefPtr<Element> button = aDoc->CreateHTMLElement(nsGkAtoms::button);
|
||||
// NOTE: SetIsNativeAnonymousRoot() has to be called before setting any
|
||||
// attribute.
|
||||
button->SetIsNativeAnonymousRoot();
|
||||
button->SetAttr(kNameSpaceID_None, nsGkAtoms::type,
|
||||
NS_LITERAL_STRING("button"), false);
|
||||
|
||||
// Set the file picking button text depending on the current locale.
|
||||
nsXPIDLString buttonTxt;
|
||||
nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
|
||||
labelKey, buttonTxt);
|
||||
|
||||
// Set the browse button text. It's a bit of a pain to do because we want to
|
||||
// make sure we are not notifying.
|
||||
RefPtr<nsTextNode> textContent =
|
||||
new nsTextNode(button->NodeInfo()->NodeInfoManager());
|
||||
|
||||
textContent->SetText(buttonTxt, false);
|
||||
|
||||
nsresult rv = button->AppendChildTo(textContent, false);
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Make sure access key and tab order for the element actually redirect to the
|
||||
// file picking button.
|
||||
RefPtr<HTMLButtonElement> buttonElement =
|
||||
HTMLButtonElement::FromContentOrNull(button);
|
||||
|
||||
if (!aAccessKey.IsEmpty()) {
|
||||
buttonElement->SetAccessKey(aAccessKey);
|
||||
}
|
||||
|
||||
// Both elements are given the same tab index so that the user can tab
|
||||
// to the file control at the correct index, and then between the two
|
||||
// buttons.
|
||||
int32_t tabIndex;
|
||||
aInputElement->GetTabIndex(&tabIndex);
|
||||
buttonElement->SetTabIndex(tabIndex);
|
||||
|
||||
return button.forget();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFileControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
|
||||
{
|
||||
nsCOMPtr<nsIDocument> doc = mContent->GetComposedDoc();
|
||||
|
||||
RefPtr<HTMLInputElement> fileContent = HTMLInputElement::FromContentOrNull(mContent);
|
||||
|
||||
// The access key is transferred to the "Choose files..." button only. In
|
||||
// effect that access key allows access to the control via that button, then
|
||||
// the user can tab between the two buttons.
|
||||
nsAutoString accessKey;
|
||||
fileContent->GetAccessKey(accessKey);
|
||||
|
||||
mBrowseFilesOrDirs = MakeAnonButton(doc, "Browse", fileContent, accessKey);
|
||||
if (!mBrowseFilesOrDirs || !aElements.AppendElement(mBrowseFilesOrDirs)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Create and setup the text showing the selected files.
|
||||
RefPtr<NodeInfo> nodeInfo;
|
||||
nodeInfo = doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::label, nullptr,
|
||||
kNameSpaceID_XUL,
|
||||
nsIDOMNode::ELEMENT_NODE);
|
||||
NS_TrustedNewXULElement(getter_AddRefs(mTextContent), nodeInfo.forget());
|
||||
// NOTE: SetIsNativeAnonymousRoot() has to be called before setting any
|
||||
// attribute.
|
||||
mTextContent->SetIsNativeAnonymousRoot();
|
||||
mTextContent->SetAttr(kNameSpaceID_None, nsGkAtoms::crop,
|
||||
NS_LITERAL_STRING("center"), false);
|
||||
|
||||
// Update the displayed text to reflect the current element's value.
|
||||
nsAutoString value;
|
||||
HTMLInputElement::FromContent(mContent)->GetDisplayFileName(value);
|
||||
UpdateDisplayedValue(value, false);
|
||||
|
||||
if (!aElements.AppendElement(mTextContent)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// We should be able to interact with the element by doing drag and drop.
|
||||
mContent->AddSystemEventListener(NS_LITERAL_STRING("drop"),
|
||||
mMouseListener, false);
|
||||
mContent->AddSystemEventListener(NS_LITERAL_STRING("dragover"),
|
||||
mMouseListener, false);
|
||||
|
||||
SyncDisabledState();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsFileControlFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
|
||||
uint32_t aFilter)
|
||||
{
|
||||
if (mBrowseFilesOrDirs) {
|
||||
aElements.AppendElement(mBrowseFilesOrDirs);
|
||||
}
|
||||
|
||||
if (mTextContent) {
|
||||
aElements.AppendElement(mTextContent);
|
||||
}
|
||||
}
|
||||
|
||||
NS_QUERYFRAME_HEAD(nsFileControlFrame)
|
||||
NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
|
||||
NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
|
||||
NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame)
|
||||
|
||||
void
|
||||
nsFileControlFrame::SetFocus(bool aOn, bool aRepaint)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
AppendBlobImplAsDirectory(nsTArray<OwningFileOrDirectory>& aArray,
|
||||
BlobImpl* aBlobImpl,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
MOZ_ASSERT(aBlobImpl);
|
||||
MOZ_ASSERT(aBlobImpl->IsDirectory());
|
||||
|
||||
nsAutoString fullpath;
|
||||
ErrorResult err;
|
||||
aBlobImpl->GetMozFullPath(fullpath, err);
|
||||
if (err.Failed()) {
|
||||
err.SuppressException();
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
NS_ConvertUTF16toUTF8 path(fullpath);
|
||||
nsresult rv = NS_NewNativeLocalFile(path, true, getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsPIDOMWindowInner* inner = aContent->OwnerDoc()->GetInnerWindow();
|
||||
if (!inner || !inner->IsCurrentInnerWindow()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<Directory> directory =
|
||||
Directory::Create(inner, file);
|
||||
MOZ_ASSERT(directory);
|
||||
|
||||
OwningFileOrDirectory* element = aArray.AppendElement();
|
||||
element->SetAsDirectory() = directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when we receive a drop or a dragover.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsFileControlFrame::DnDListener::HandleEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
NS_ASSERTION(mFrame, "We should have been unregistered");
|
||||
|
||||
bool defaultPrevented = false;
|
||||
aEvent->GetDefaultPrevented(&defaultPrevented);
|
||||
if (defaultPrevented) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
|
||||
if (!dragEvent) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
|
||||
dragEvent->GetDataTransfer(getter_AddRefs(dataTransfer));
|
||||
if (!IsValidDropData(dataTransfer)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsCOMPtr<nsIContent> content = mFrame->GetContent();
|
||||
bool supportsMultiple = content && content->HasAttr(kNameSpaceID_None, nsGkAtoms::multiple);
|
||||
if (!CanDropTheseFiles(dataTransfer, supportsMultiple)) {
|
||||
dataTransfer->SetDropEffect(NS_LITERAL_STRING("none"));
|
||||
aEvent->StopPropagation();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoString eventType;
|
||||
aEvent->GetType(eventType);
|
||||
if (eventType.EqualsLiteral("dragover")) {
|
||||
// Prevent default if we can accept this drag data
|
||||
aEvent->PreventDefault();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (eventType.EqualsLiteral("drop")) {
|
||||
aEvent->StopPropagation();
|
||||
aEvent->PreventDefault();
|
||||
|
||||
NS_ASSERTION(content, "The frame has no content???");
|
||||
|
||||
HTMLInputElement* inputElement = HTMLInputElement::FromContent(content);
|
||||
NS_ASSERTION(inputElement, "No input element for this file upload control frame!");
|
||||
|
||||
nsCOMPtr<nsIDOMFileList> fileList;
|
||||
dataTransfer->GetFiles(getter_AddRefs(fileList));
|
||||
|
||||
RefPtr<BlobImpl> webkitDir;
|
||||
nsresult rv =
|
||||
GetBlobImplForWebkitDirectory(fileList, getter_AddRefs(webkitDir));
|
||||
NS_ENSURE_SUCCESS(rv, NS_OK);
|
||||
|
||||
nsTArray<OwningFileOrDirectory> array;
|
||||
if (webkitDir) {
|
||||
AppendBlobImplAsDirectory(array, webkitDir, content);
|
||||
inputElement->MozSetDndFilesAndDirectories(array);
|
||||
} else {
|
||||
bool blinkFileSystemEnabled =
|
||||
Preferences::GetBool("dom.webkitBlink.filesystem.enabled", false);
|
||||
if (blinkFileSystemEnabled) {
|
||||
FileList* files = static_cast<FileList*>(fileList.get());
|
||||
if (files) {
|
||||
for (uint32_t i = 0; i < files->Length(); ++i) {
|
||||
File* file = files->Item(i);
|
||||
if (file) {
|
||||
if (file->Impl() && file->Impl()->IsDirectory()) {
|
||||
AppendBlobImplAsDirectory(array, file->Impl(), content);
|
||||
} else {
|
||||
OwningFileOrDirectory* element = array.AppendElement();
|
||||
element->SetAsFile() = file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is rather ugly. Pass the directories as Files using SetFiles,
|
||||
// but then if blink filesystem API is enabled, it wants
|
||||
// FileOrDirectory array.
|
||||
inputElement->SetFiles(fileList, true);
|
||||
if (blinkFileSystemEnabled) {
|
||||
inputElement->UpdateEntries(array);
|
||||
}
|
||||
nsContentUtils::DispatchTrustedEvent(content->OwnerDoc(), content,
|
||||
NS_LITERAL_STRING("input"), true,
|
||||
false);
|
||||
nsContentUtils::DispatchTrustedEvent(content->OwnerDoc(), content,
|
||||
NS_LITERAL_STRING("change"), true,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFileControlFrame::DnDListener::GetBlobImplForWebkitDirectory(nsIDOMFileList* aFileList,
|
||||
BlobImpl** aBlobImpl)
|
||||
{
|
||||
*aBlobImpl = nullptr;
|
||||
|
||||
HTMLInputElement* inputElement =
|
||||
HTMLInputElement::FromContent(mFrame->GetContent());
|
||||
bool webkitDirPicker =
|
||||
Preferences::GetBool("dom.webkitBlink.dirPicker.enabled", false) &&
|
||||
inputElement->HasAttr(kNameSpaceID_None, nsGkAtoms::webkitdirectory);
|
||||
if (!webkitDirPicker) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!aFileList) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
FileList* files = static_cast<FileList*>(aFileList);
|
||||
// webkitdirectory doesn't care about the length of the file list but
|
||||
// only about the first item on it.
|
||||
uint32_t len = files->Length();
|
||||
if (len) {
|
||||
File* file = files->Item(0);
|
||||
if (file) {
|
||||
BlobImpl* impl = file->Impl();
|
||||
if (impl && impl->IsDirectory()) {
|
||||
RefPtr<BlobImpl> retVal = impl;
|
||||
retVal.swap(*aBlobImpl);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool
|
||||
nsFileControlFrame::DnDListener::IsValidDropData(nsIDOMDataTransfer* aDOMDataTransfer)
|
||||
{
|
||||
nsCOMPtr<DataTransfer> dataTransfer = do_QueryInterface(aDOMDataTransfer);
|
||||
NS_ENSURE_TRUE(dataTransfer, false);
|
||||
|
||||
// We only support dropping files onto a file upload control
|
||||
nsTArray<nsString> types;
|
||||
dataTransfer->GetTypes(types, *nsContentUtils::GetSystemPrincipal());
|
||||
|
||||
return types.Contains(NS_LITERAL_STRING("Files"));
|
||||
}
|
||||
|
||||
bool
|
||||
nsFileControlFrame::DnDListener::CanDropTheseFiles(nsIDOMDataTransfer* aDOMDataTransfer,
|
||||
bool aSupportsMultiple)
|
||||
{
|
||||
nsCOMPtr<DataTransfer> dataTransfer = do_QueryInterface(aDOMDataTransfer);
|
||||
NS_ENSURE_TRUE(dataTransfer, false);
|
||||
|
||||
nsCOMPtr<nsIDOMFileList> fileList;
|
||||
dataTransfer->GetFiles(getter_AddRefs(fileList));
|
||||
|
||||
RefPtr<BlobImpl> webkitDir;
|
||||
nsresult rv =
|
||||
GetBlobImplForWebkitDirectory(fileList, getter_AddRefs(webkitDir));
|
||||
// Just check if either there isn't webkitdirectory attribute, or
|
||||
// fileList has a directory which can be dropped to the element.
|
||||
// No need to use webkitDir for anything here.
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
uint32_t listLength = 0;
|
||||
if (fileList) {
|
||||
fileList->GetLength(&listLength);
|
||||
}
|
||||
return listLength <= 1 || aSupportsMultiple;
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFileControlFrame::GetMinISize(nsRenderingContext *aRenderingContext)
|
||||
{
|
||||
nscoord result;
|
||||
DISPLAY_MIN_WIDTH(this, result);
|
||||
|
||||
// Our min width is our pref width
|
||||
result = GetPrefISize(aRenderingContext);
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
nsFileControlFrame::SyncDisabledState()
|
||||
{
|
||||
EventStates eventStates = mContent->AsElement()->State();
|
||||
if (eventStates.HasState(NS_EVENT_STATE_DISABLED)) {
|
||||
mBrowseFilesOrDirs->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled,
|
||||
EmptyString(), true);
|
||||
} else {
|
||||
mBrowseFilesOrDirs->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, true);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFileControlFrame::AttributeChanged(int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
{
|
||||
if (aNameSpaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::tabindex) {
|
||||
if (aModType == nsIDOMMutationEvent::REMOVAL) {
|
||||
mBrowseFilesOrDirs->UnsetAttr(aNameSpaceID, aAttribute, true);
|
||||
} else {
|
||||
nsAutoString value;
|
||||
mContent->GetAttr(aNameSpaceID, aAttribute, value);
|
||||
mBrowseFilesOrDirs->SetAttr(aNameSpaceID, aAttribute, value, true);
|
||||
}
|
||||
}
|
||||
|
||||
return nsBlockFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
|
||||
}
|
||||
|
||||
void
|
||||
nsFileControlFrame::ContentStatesChanged(EventStates aStates)
|
||||
{
|
||||
if (aStates.HasState(NS_EVENT_STATE_DISABLED)) {
|
||||
nsContentUtils::AddScriptRunner(new SyncDisabledStateEvent(this));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
nsresult
|
||||
nsFileControlFrame::GetFrameName(nsAString& aResult) const
|
||||
{
|
||||
return MakeFrameName(NS_LITERAL_STRING("FileControl"), aResult);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
nsFileControlFrame::UpdateDisplayedValue(const nsAString& aValue, bool aNotify)
|
||||
{
|
||||
mTextContent->SetAttr(kNameSpaceID_None, nsGkAtoms::value, aValue, aNotify);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFileControlFrame::SetFormProperty(nsIAtom* aName,
|
||||
const nsAString& aValue)
|
||||
{
|
||||
if (nsGkAtoms::value == aName) {
|
||||
UpdateDisplayedValue(aValue, true);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsFileControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists)
|
||||
{
|
||||
BuildDisplayListForInline(aBuilder, aDirtyRect, aLists);
|
||||
}
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
a11y::AccType
|
||||
nsFileControlFrame::AccessibleType()
|
||||
{
|
||||
return a11y::eHTMLFileInputType;
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Mouse listener implementation
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsFileControlFrame::MouseListener,
|
||||
nsIDOMEventListener)
|
||||
167
layout/forms/nsFileControlFrame.h
Normal file
167
layout/forms/nsFileControlFrame.h
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsFileControlFrame_h___
|
||||
#define nsFileControlFrame_h___
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsBlockFrame.h"
|
||||
#include "nsIFormControlFrame.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsIAnonymousContentCreator.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsIDOMDataTransfer;
|
||||
class nsIDOMFileList;
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class BlobImpl;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
class nsFileControlFrame : public nsBlockFrame,
|
||||
public nsIFormControlFrame,
|
||||
public nsIAnonymousContentCreator
|
||||
{
|
||||
public:
|
||||
explicit nsFileControlFrame(nsStyleContext* aContext);
|
||||
|
||||
virtual void Init(nsIContent* aContent,
|
||||
nsContainerFrame* aParent,
|
||||
nsIFrame* aPrevInFlow) override;
|
||||
|
||||
virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists) override;
|
||||
|
||||
NS_DECL_QUERYFRAME
|
||||
NS_DECL_FRAMEARENA_HELPERS
|
||||
|
||||
// nsIFormControlFrame
|
||||
virtual nsresult SetFormProperty(nsIAtom* aName, const nsAString& aValue) override;
|
||||
virtual void SetFocus(bool aOn, bool aRepaint) override;
|
||||
|
||||
virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) override;
|
||||
|
||||
virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
|
||||
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
virtual nsresult GetFrameName(nsAString& aResult) const override;
|
||||
#endif
|
||||
|
||||
virtual nsresult AttributeChanged(int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType) override;
|
||||
virtual void ContentStatesChanged(mozilla::EventStates aStates) override;
|
||||
virtual bool IsLeaf() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// nsIAnonymousContentCreator
|
||||
virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
|
||||
virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
|
||||
uint32_t aFilter) override;
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
virtual mozilla::a11y::AccType AccessibleType() override;
|
||||
#endif
|
||||
|
||||
typedef bool (*AcceptAttrCallback)(const nsAString&, void*);
|
||||
|
||||
protected:
|
||||
|
||||
class MouseListener;
|
||||
friend class MouseListener;
|
||||
class MouseListener : public nsIDOMEventListener {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
explicit MouseListener(nsFileControlFrame* aFrame)
|
||||
: mFrame(aFrame)
|
||||
{}
|
||||
|
||||
void ForgetFrame() {
|
||||
mFrame = nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~MouseListener() {}
|
||||
|
||||
nsFileControlFrame* mFrame;
|
||||
};
|
||||
|
||||
class SyncDisabledStateEvent;
|
||||
friend class SyncDisabledStateEvent;
|
||||
class SyncDisabledStateEvent : public mozilla::Runnable
|
||||
{
|
||||
public:
|
||||
explicit SyncDisabledStateEvent(nsFileControlFrame* aFrame)
|
||||
: mFrame(aFrame)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run() override {
|
||||
nsFileControlFrame* frame = static_cast<nsFileControlFrame*>(mFrame.GetFrame());
|
||||
NS_ENSURE_STATE(frame);
|
||||
|
||||
frame->SyncDisabledState();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsWeakFrame mFrame;
|
||||
};
|
||||
|
||||
class DnDListener: public MouseListener {
|
||||
public:
|
||||
explicit DnDListener(nsFileControlFrame* aFrame)
|
||||
: MouseListener(aFrame)
|
||||
{}
|
||||
|
||||
NS_DECL_NSIDOMEVENTLISTENER
|
||||
|
||||
nsresult GetBlobImplForWebkitDirectory(nsIDOMFileList* aFileList,
|
||||
mozilla::dom::BlobImpl** aBlobImpl);
|
||||
|
||||
bool IsValidDropData(nsIDOMDataTransfer* aDOMDataTransfer);
|
||||
bool CanDropTheseFiles(nsIDOMDataTransfer* aDOMDataTransfer, bool aSupportsMultiple);
|
||||
};
|
||||
|
||||
virtual bool IsFrameOfType(uint32_t aFlags) const override
|
||||
{
|
||||
return nsBlockFrame::IsFrameOfType(aFlags &
|
||||
~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
|
||||
}
|
||||
|
||||
/**
|
||||
* The text box input.
|
||||
* @see nsFileControlFrame::CreateAnonymousContent
|
||||
*/
|
||||
nsCOMPtr<nsIContent> mTextContent;
|
||||
/**
|
||||
* The button to open a file or directory picker.
|
||||
* @see nsFileControlFrame::CreateAnonymousContent
|
||||
*/
|
||||
nsCOMPtr<nsIContent> mBrowseFilesOrDirs;
|
||||
|
||||
/**
|
||||
* Drag and drop mouse listener.
|
||||
* This makes sure we don't get used after destruction.
|
||||
*/
|
||||
RefPtr<DnDListener> mMouseListener;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Sync the disabled state of the content with anonymous children.
|
||||
*/
|
||||
void SyncDisabledState();
|
||||
|
||||
/**
|
||||
* Updates the displayed value by using aValue.
|
||||
*/
|
||||
void UpdateDisplayedValue(const nsAString& aValue, bool aNotify);
|
||||
};
|
||||
|
||||
#endif // nsFileControlFrame_h___
|
||||
225
layout/forms/nsFormControlFrame.cpp
Normal file
225
layout/forms/nsFormControlFrame.cpp
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsFormControlFrame.h"
|
||||
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsIDOMHTMLInputElement.h"
|
||||
#include "mozilla/EventStateManager.h"
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
#include "nsDeviceContext.h"
|
||||
#include "nsIContent.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
//#define FCF_NOISY
|
||||
|
||||
nsFormControlFrame::nsFormControlFrame(nsStyleContext* aContext)
|
||||
: nsAtomicContainerFrame(aContext)
|
||||
{
|
||||
}
|
||||
|
||||
nsFormControlFrame::~nsFormControlFrame()
|
||||
{
|
||||
}
|
||||
|
||||
nsIAtom*
|
||||
nsFormControlFrame::GetType() const
|
||||
{
|
||||
return nsGkAtoms::formControlFrame;
|
||||
}
|
||||
|
||||
void
|
||||
nsFormControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
|
||||
{
|
||||
// Unregister the access key registered in reflow
|
||||
nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false);
|
||||
nsAtomicContainerFrame::DestroyFrom(aDestructRoot);
|
||||
}
|
||||
|
||||
NS_QUERYFRAME_HEAD(nsFormControlFrame)
|
||||
NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
|
||||
NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame)
|
||||
|
||||
/* virtual */ nscoord
|
||||
nsFormControlFrame::GetMinISize(nsRenderingContext *aRenderingContext)
|
||||
{
|
||||
nscoord result;
|
||||
DISPLAY_MIN_WIDTH(this, result);
|
||||
result = GetIntrinsicISize();
|
||||
return result;
|
||||
}
|
||||
|
||||
/* virtual */ nscoord
|
||||
nsFormControlFrame::GetPrefISize(nsRenderingContext *aRenderingContext)
|
||||
{
|
||||
nscoord result;
|
||||
DISPLAY_PREF_WIDTH(this, result);
|
||||
result = GetIntrinsicISize();
|
||||
return result;
|
||||
}
|
||||
|
||||
/* virtual */
|
||||
LogicalSize
|
||||
nsFormControlFrame::ComputeAutoSize(nsRenderingContext* aRenderingContext,
|
||||
WritingMode aWM,
|
||||
const LogicalSize& aCBSize,
|
||||
nscoord aAvailableISize,
|
||||
const LogicalSize& aMargin,
|
||||
const LogicalSize& aBorder,
|
||||
const LogicalSize& aPadding,
|
||||
ComputeSizeFlags aFlags)
|
||||
{
|
||||
const WritingMode wm = GetWritingMode();
|
||||
LogicalSize result(wm, GetIntrinsicISize(), GetIntrinsicBSize());
|
||||
return result.ConvertTo(aWM, wm);
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFormControlFrame::GetIntrinsicISize()
|
||||
{
|
||||
// Provide a reasonable default for sites that use an "auto" height.
|
||||
// Note that if you change this, you should change the values in forms.css
|
||||
// as well. This is the 13px default width minus the 2px default border.
|
||||
return nsPresContext::CSSPixelsToAppUnits(13 - 2 * 2);
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFormControlFrame::GetIntrinsicBSize()
|
||||
{
|
||||
// Provide a reasonable default for sites that use an "auto" height.
|
||||
// Note that if you change this, you should change the values in forms.css
|
||||
// as well. This is the 13px default width minus the 2px default border.
|
||||
return nsPresContext::CSSPixelsToAppUnits(13 - 2 * 2);
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFormControlFrame::GetLogicalBaseline(WritingMode aWritingMode) const
|
||||
{
|
||||
NS_ASSERTION(!NS_SUBTREE_DIRTY(this),
|
||||
"frame must not be dirty");
|
||||
// Treat radio buttons and checkboxes as having an intrinsic baseline
|
||||
// at the block-end of the control (use the block-end content edge rather
|
||||
// than the margin edge).
|
||||
// For "inverted" lines (typically in writing-mode:vertical-lr), use the
|
||||
// block-start end instead.
|
||||
return aWritingMode.IsLineInverted()
|
||||
? GetLogicalUsedBorderAndPadding(aWritingMode).BStart(aWritingMode)
|
||||
: BSize(aWritingMode) -
|
||||
GetLogicalUsedBorderAndPadding(aWritingMode).BEnd(aWritingMode);
|
||||
}
|
||||
|
||||
void
|
||||
nsFormControlFrame::Reflow(nsPresContext* aPresContext,
|
||||
ReflowOutput& aDesiredSize,
|
||||
const ReflowInput& aReflowInput,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
MarkInReflow();
|
||||
DO_GLOBAL_REFLOW_COUNT("nsFormControlFrame");
|
||||
DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
|
||||
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
||||
("enter nsFormControlFrame::Reflow: aMaxSize=%d,%d",
|
||||
aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight()));
|
||||
|
||||
if (mState & NS_FRAME_FIRST_REFLOW) {
|
||||
RegUnRegAccessKey(static_cast<nsIFrame*>(this), true);
|
||||
}
|
||||
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
aDesiredSize.SetSize(aReflowInput.GetWritingMode(),
|
||||
aReflowInput.ComputedSizeWithBorderPadding());
|
||||
|
||||
if (nsLayoutUtils::FontSizeInflationEnabled(aPresContext)) {
|
||||
float inflation = nsLayoutUtils::FontSizeInflationFor(this);
|
||||
aDesiredSize.Width() *= inflation;
|
||||
aDesiredSize.Height() *= inflation;
|
||||
}
|
||||
|
||||
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
||||
("exit nsFormControlFrame::Reflow: size=%d,%d",
|
||||
aDesiredSize.Width(), aDesiredSize.Height()));
|
||||
NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
|
||||
|
||||
aDesiredSize.SetOverflowAreasToDesiredBounds();
|
||||
FinishAndStoreOverflow(&aDesiredSize);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFormControlFrame::RegUnRegAccessKey(nsIFrame * aFrame, bool aDoReg)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aFrame);
|
||||
|
||||
nsPresContext* presContext = aFrame->PresContext();
|
||||
|
||||
NS_ASSERTION(presContext, "aPresContext is NULL in RegUnRegAccessKey!");
|
||||
|
||||
nsAutoString accessKey;
|
||||
|
||||
nsIContent* content = aFrame->GetContent();
|
||||
content->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, accessKey);
|
||||
if (!accessKey.IsEmpty()) {
|
||||
EventStateManager* stateManager = presContext->EventStateManager();
|
||||
if (aDoReg) {
|
||||
stateManager->RegisterAccessKey(content, (uint32_t)accessKey.First());
|
||||
} else {
|
||||
stateManager->UnregisterAccessKey(content, (uint32_t)accessKey.First());
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
void
|
||||
nsFormControlFrame::SetFocus(bool aOn, bool aRepaint)
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFormControlFrame::HandleEvent(nsPresContext* aPresContext,
|
||||
WidgetGUIEvent* aEvent,
|
||||
nsEventStatus* aEventStatus)
|
||||
{
|
||||
// Check for user-input:none style
|
||||
const nsStyleUserInterface* uiStyle = StyleUserInterface();
|
||||
if (uiStyle->mUserInput == StyleUserInput::None ||
|
||||
uiStyle->mUserInput == StyleUserInput::Disabled) {
|
||||
return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsFormControlFrame::GetCurrentCheckState(bool *aState)
|
||||
{
|
||||
nsCOMPtr<nsIDOMHTMLInputElement> inputElement = do_QueryInterface(mContent);
|
||||
if (inputElement) {
|
||||
inputElement->GetChecked(aState);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFormControlFrame::SetFormProperty(nsIAtom* aName, const nsAString& aValue)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsRect
|
||||
nsFormControlFrame::GetUsableScreenRect(nsPresContext* aPresContext)
|
||||
{
|
||||
nsRect screen;
|
||||
|
||||
nsDeviceContext *context = aPresContext->DeviceContext();
|
||||
int32_t dropdownCanOverlapOSBar =
|
||||
LookAndFeel::GetInt(LookAndFeel::eIntID_MenusCanOverlapOSBar, 0);
|
||||
if ( dropdownCanOverlapOSBar )
|
||||
context->GetRect(screen);
|
||||
else
|
||||
context->GetClientRect(screen);
|
||||
|
||||
return screen;
|
||||
}
|
||||
129
layout/forms/nsFormControlFrame.h
Normal file
129
layout/forms/nsFormControlFrame.h
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsFormControlFrame_h___
|
||||
#define nsFormControlFrame_h___
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsIFormControlFrame.h"
|
||||
#include "nsAtomicContainerFrame.h"
|
||||
#include "nsDisplayList.h"
|
||||
|
||||
/**
|
||||
* nsFormControlFrame is the base class for radio buttons and
|
||||
* checkboxes. It also has two static methods (RegUnRegAccessKey and
|
||||
* GetScreenHeight) that are used by other form controls.
|
||||
*/
|
||||
class nsFormControlFrame : public nsAtomicContainerFrame,
|
||||
public nsIFormControlFrame
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Main constructor
|
||||
* @param aContent the content representing this frame
|
||||
* @param aParentFrame the parent frame
|
||||
*/
|
||||
explicit nsFormControlFrame(nsStyleContext*);
|
||||
|
||||
virtual nsIAtom* GetType() const override;
|
||||
|
||||
virtual bool IsFrameOfType(uint32_t aFlags) const override
|
||||
{
|
||||
return nsAtomicContainerFrame::IsFrameOfType(aFlags &
|
||||
~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
|
||||
}
|
||||
|
||||
NS_DECL_QUERYFRAME
|
||||
NS_DECL_ABSTRACT_FRAME(nsFormControlFrame)
|
||||
|
||||
// nsIFrame replacements
|
||||
virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists) override {
|
||||
DO_GLOBAL_REFLOW_COUNT_DSP("nsFormControlFrame");
|
||||
DisplayBorderBackgroundOutline(aBuilder, aLists);
|
||||
}
|
||||
|
||||
/**
|
||||
* Both GetMinISize and GetPrefISize will return whatever GetIntrinsicISize
|
||||
* returns.
|
||||
*/
|
||||
virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) override;
|
||||
virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext) override;
|
||||
|
||||
/**
|
||||
* Our auto size is just intrinsic width and intrinsic height.
|
||||
*/
|
||||
virtual mozilla::LogicalSize
|
||||
ComputeAutoSize(nsRenderingContext* aRenderingContext,
|
||||
mozilla::WritingMode aWM,
|
||||
const mozilla::LogicalSize& aCBSize,
|
||||
nscoord aAvailableISize,
|
||||
const mozilla::LogicalSize& aMargin,
|
||||
const mozilla::LogicalSize& aBorder,
|
||||
const mozilla::LogicalSize& aPadding,
|
||||
ComputeSizeFlags aFlags) override;
|
||||
|
||||
/**
|
||||
* Respond to a gui event
|
||||
* @see nsIFrame::HandleEvent
|
||||
*/
|
||||
virtual nsresult HandleEvent(nsPresContext* aPresContext,
|
||||
mozilla::WidgetGUIEvent* aEvent,
|
||||
nsEventStatus* aEventStatus) override;
|
||||
|
||||
virtual nscoord GetLogicalBaseline(mozilla::WritingMode aWritingMode)
|
||||
const override;
|
||||
|
||||
/**
|
||||
* Respond to the request to resize and/or reflow
|
||||
* @see nsIFrame::Reflow
|
||||
*/
|
||||
virtual void Reflow(nsPresContext* aCX,
|
||||
ReflowOutput& aDesiredSize,
|
||||
const ReflowInput& aReflowInput,
|
||||
nsReflowStatus& aStatus) override;
|
||||
|
||||
virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
|
||||
|
||||
// new behavior
|
||||
|
||||
virtual void SetFocus(bool aOn = true, bool aRepaint = false) override;
|
||||
|
||||
// nsIFormControlFrame
|
||||
virtual nsresult SetFormProperty(nsIAtom* aName, const nsAString& aValue) override;
|
||||
|
||||
// AccessKey Helper function
|
||||
static nsresult RegUnRegAccessKey(nsIFrame * aFrame, bool aDoReg);
|
||||
|
||||
/**
|
||||
* Returns the usable screen rect in app units, eg the rect where we can
|
||||
* draw dropdowns.
|
||||
*/
|
||||
static nsRect GetUsableScreenRect(nsPresContext* aPresContext);
|
||||
|
||||
protected:
|
||||
|
||||
virtual ~nsFormControlFrame();
|
||||
|
||||
nscoord GetIntrinsicISize();
|
||||
nscoord GetIntrinsicBSize();
|
||||
|
||||
//
|
||||
//-------------------------------------------------------------------------------------
|
||||
// Utility methods for managing checkboxes and radiobuttons
|
||||
//-------------------------------------------------------------------------------------
|
||||
//
|
||||
/**
|
||||
* Get the state of the checked attribute.
|
||||
* @param aState set to true if the checked attribute is set,
|
||||
* false if the checked attribute has been removed
|
||||
*/
|
||||
|
||||
void GetCurrentCheckState(bool* aState);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
237
layout/forms/nsGfxButtonControlFrame.cpp
Normal file
237
layout/forms/nsGfxButtonControlFrame.cpp
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsGfxButtonControlFrame.h"
|
||||
#include "nsIFormControl.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "mozilla/StyleSetHandle.h"
|
||||
#include "mozilla/StyleSetHandleInlines.h"
|
||||
#include "nsContentUtils.h"
|
||||
// MouseEvent suppression in PP
|
||||
#include "nsContentList.h"
|
||||
|
||||
#include "nsIDOMHTMLInputElement.h"
|
||||
#include "nsTextNode.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
nsGfxButtonControlFrame::nsGfxButtonControlFrame(nsStyleContext* aContext):
|
||||
nsHTMLButtonControlFrame(aContext)
|
||||
{
|
||||
}
|
||||
|
||||
nsContainerFrame*
|
||||
NS_NewGfxButtonControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
|
||||
{
|
||||
return new (aPresShell) nsGfxButtonControlFrame(aContext);
|
||||
}
|
||||
|
||||
NS_IMPL_FRAMEARENA_HELPERS(nsGfxButtonControlFrame)
|
||||
|
||||
void nsGfxButtonControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
|
||||
{
|
||||
nsContentUtils::DestroyAnonymousContent(&mTextContent);
|
||||
nsHTMLButtonControlFrame::DestroyFrom(aDestructRoot);
|
||||
}
|
||||
|
||||
nsIAtom*
|
||||
nsGfxButtonControlFrame::GetType() const
|
||||
{
|
||||
return nsGkAtoms::gfxButtonControlFrame;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
nsresult
|
||||
nsGfxButtonControlFrame::GetFrameName(nsAString& aResult) const
|
||||
{
|
||||
return MakeFrameName(NS_LITERAL_STRING("ButtonControl"), aResult);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Create the text content used as label for the button.
|
||||
// The frame will be generated by the frame constructor.
|
||||
nsresult
|
||||
nsGfxButtonControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
|
||||
{
|
||||
nsXPIDLString label;
|
||||
GetLabel(label);
|
||||
|
||||
// Add a child text content node for the label
|
||||
mTextContent = new nsTextNode(mContent->NodeInfo()->NodeInfoManager());
|
||||
|
||||
// set the value of the text node and add it to the child list
|
||||
mTextContent->SetText(label, false);
|
||||
aElements.AppendElement(mTextContent);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsGfxButtonControlFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
|
||||
uint32_t aFilter)
|
||||
{
|
||||
if (mTextContent) {
|
||||
aElements.AppendElement(mTextContent);
|
||||
}
|
||||
}
|
||||
|
||||
// Create the text content used as label for the button.
|
||||
// The frame will be generated by the frame constructor.
|
||||
nsIFrame*
|
||||
nsGfxButtonControlFrame::CreateFrameFor(nsIContent* aContent)
|
||||
{
|
||||
nsIFrame * newFrame = nullptr;
|
||||
|
||||
if (aContent == mTextContent) {
|
||||
nsContainerFrame* parentFrame = do_QueryFrame(mFrames.FirstChild());
|
||||
|
||||
nsPresContext* presContext = PresContext();
|
||||
RefPtr<nsStyleContext> textStyleContext;
|
||||
textStyleContext = presContext->StyleSet()->
|
||||
ResolveStyleForText(mTextContent, mStyleContext);
|
||||
|
||||
newFrame = NS_NewTextFrame(presContext->PresShell(), textStyleContext);
|
||||
// initialize the text frame
|
||||
newFrame->Init(mTextContent, parentFrame, nullptr);
|
||||
mTextContent->SetPrimaryFrame(newFrame);
|
||||
}
|
||||
|
||||
return newFrame;
|
||||
}
|
||||
|
||||
NS_QUERYFRAME_HEAD(nsGfxButtonControlFrame)
|
||||
NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
|
||||
NS_QUERYFRAME_TAIL_INHERITING(nsHTMLButtonControlFrame)
|
||||
|
||||
// Initially we hardcoded the default strings here.
|
||||
// Next, we used html.css to store the default label for various types
|
||||
// of buttons. (nsGfxButtonControlFrame::DoNavQuirksReflow rev 1.20)
|
||||
// However, since html.css is not internationalized, we now grab the default
|
||||
// label from a string bundle as is done for all other UI strings.
|
||||
// See bug 16999 for further details.
|
||||
nsresult
|
||||
nsGfxButtonControlFrame::GetDefaultLabel(nsXPIDLString& aString) const
|
||||
{
|
||||
nsCOMPtr<nsIFormControl> form = do_QueryInterface(mContent);
|
||||
NS_ENSURE_TRUE(form, NS_ERROR_UNEXPECTED);
|
||||
|
||||
int32_t type = form->GetType();
|
||||
const char *prop;
|
||||
if (type == NS_FORM_INPUT_RESET) {
|
||||
prop = "Reset";
|
||||
}
|
||||
else if (type == NS_FORM_INPUT_SUBMIT) {
|
||||
prop = "Submit";
|
||||
}
|
||||
else {
|
||||
aString.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
|
||||
prop, aString);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGfxButtonControlFrame::GetLabel(nsXPIDLString& aLabel)
|
||||
{
|
||||
// Get the text from the "value" property on our content if there is
|
||||
// one; otherwise set it to a default value (localized).
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMHTMLInputElement> elt = do_QueryInterface(mContent);
|
||||
if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::value) && elt) {
|
||||
rv = elt->GetValue(aLabel);
|
||||
} else {
|
||||
// Generate localized label.
|
||||
// We can't make any assumption as to what the default would be
|
||||
// because the value is localized for non-english platforms, thus
|
||||
// it might not be the string "Reset", "Submit Query", or "Browse..."
|
||||
rv = GetDefaultLabel(aLabel);
|
||||
}
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Compress whitespace out of label if needed.
|
||||
if (!StyleText()->WhiteSpaceIsSignificant()) {
|
||||
aLabel.CompressWhitespace();
|
||||
} else if (aLabel.Length() > 2 && aLabel.First() == ' ' &&
|
||||
aLabel.CharAt(aLabel.Length() - 1) == ' ') {
|
||||
// This is a bit of a hack. The reason this is here is as follows: we now
|
||||
// have default padding on our buttons to make them non-ugly.
|
||||
// Unfortunately, IE-windows does not have such padding, so people will
|
||||
// stick values like " ok " (with the spaces) in the buttons in an attempt
|
||||
// to make them look decent. Unfortunately, if they do this the button
|
||||
// looks way too big in Mozilla. Worse yet, if they do this _and_ set a
|
||||
// fixed width for the button we run into trouble because our focus-rect
|
||||
// border/padding and outer border take up 10px of the horizontal button
|
||||
// space or so; the result is that the text is misaligned, even with the
|
||||
// recentering we do in nsHTMLButtonControlFrame::Reflow. So to solve
|
||||
// this, even if the whitespace is significant, single leading and trailing
|
||||
// _spaces_ (and not other whitespace) are removed. The proper solution,
|
||||
// of course, is to not have the focus rect painting taking up 6px of
|
||||
// horizontal space. We should do that instead (via XBL form controls or
|
||||
// changing the renderer) and remove this.
|
||||
aLabel.Cut(0, 1);
|
||||
aLabel.Truncate(aLabel.Length() - 1);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGfxButtonControlFrame::AttributeChanged(int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// If the value attribute is set, update the text of the label
|
||||
if (nsGkAtoms::value == aAttribute) {
|
||||
if (mTextContent && mContent) {
|
||||
nsXPIDLString label;
|
||||
rv = GetLabel(label);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mTextContent->SetText(label, true);
|
||||
} else {
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// defer to HTMLButtonControlFrame
|
||||
} else {
|
||||
rv = nsHTMLButtonControlFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool
|
||||
nsGfxButtonControlFrame::IsLeaf() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
nsContainerFrame*
|
||||
nsGfxButtonControlFrame::GetContentInsertionFrame()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGfxButtonControlFrame::HandleEvent(nsPresContext* aPresContext,
|
||||
WidgetGUIEvent* aEvent,
|
||||
nsEventStatus* aEventStatus)
|
||||
{
|
||||
// Override the HandleEvent to prevent the nsFrame::HandleEvent
|
||||
// from being called. The nsFrame::HandleEvent causes the button label
|
||||
// to be selected (Drawn with an XOR rectangle over the label)
|
||||
|
||||
// do we have user-input style?
|
||||
const nsStyleUserInterface* uiStyle = StyleUserInterface();
|
||||
if (uiStyle->mUserInput == StyleUserInput::None ||
|
||||
uiStyle->mUserInput == StyleUserInput::Disabled) {
|
||||
return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
67
layout/forms/nsGfxButtonControlFrame.h
Normal file
67
layout/forms/nsGfxButtonControlFrame.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsGfxButtonControlFrame_h___
|
||||
#define nsGfxButtonControlFrame_h___
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsHTMLButtonControlFrame.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIAnonymousContentCreator.h"
|
||||
|
||||
// Class which implements the input[type=button, reset, submit] and
|
||||
// browse button for input[type=file].
|
||||
// The label for button is specified through generated content
|
||||
// in the ua.css file.
|
||||
|
||||
class nsGfxButtonControlFrame : public nsHTMLButtonControlFrame,
|
||||
public nsIAnonymousContentCreator
|
||||
{
|
||||
public:
|
||||
NS_DECL_FRAMEARENA_HELPERS
|
||||
|
||||
explicit nsGfxButtonControlFrame(nsStyleContext* aContext);
|
||||
|
||||
virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
|
||||
|
||||
virtual nsresult HandleEvent(nsPresContext* aPresContext,
|
||||
mozilla::WidgetGUIEvent* aEvent,
|
||||
nsEventStatus* aEventStatus) override;
|
||||
|
||||
virtual nsIAtom* GetType() const override;
|
||||
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
virtual nsresult GetFrameName(nsAString& aResult) const override;
|
||||
#endif
|
||||
|
||||
NS_DECL_QUERYFRAME
|
||||
|
||||
// nsIAnonymousContentCreator
|
||||
virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
|
||||
virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
|
||||
uint32_t aFilter) override;
|
||||
virtual nsIFrame* CreateFrameFor(nsIContent* aContent) override;
|
||||
|
||||
virtual nsresult AttributeChanged(int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType) override;
|
||||
|
||||
virtual bool IsLeaf() const override;
|
||||
|
||||
virtual nsContainerFrame* GetContentInsertionFrame() override;
|
||||
|
||||
protected:
|
||||
nsresult GetDefaultLabel(nsXPIDLString& aLabel) const;
|
||||
|
||||
nsresult GetLabel(nsXPIDLString& aLabel);
|
||||
|
||||
virtual bool IsInput() override { return true; }
|
||||
private:
|
||||
nsCOMPtr<nsIContent> mTextContent;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
147
layout/forms/nsGfxCheckboxControlFrame.cpp
Normal file
147
layout/forms/nsGfxCheckboxControlFrame.cpp
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsGfxCheckboxControlFrame.h"
|
||||
|
||||
#include "gfxUtils.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsRenderingContext.h"
|
||||
#include "nsIDOMHTMLInputElement.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
static void
|
||||
PaintCheckMark(nsIFrame* aFrame,
|
||||
DrawTarget* aDrawTarget,
|
||||
const nsRect& aDirtyRect,
|
||||
nsPoint aPt)
|
||||
{
|
||||
nsRect rect(aPt, aFrame->GetSize());
|
||||
rect.Deflate(aFrame->GetUsedBorderAndPadding());
|
||||
|
||||
// Points come from the coordinates on a 7X7 unit box centered at 0,0
|
||||
const int32_t checkPolygonX[] = { -3, -1, 3, 3, -1, -3 };
|
||||
const int32_t checkPolygonY[] = { -1, 1, -3, -1, 3, 1 };
|
||||
const int32_t checkNumPoints = sizeof(checkPolygonX) / sizeof(int32_t);
|
||||
const int32_t checkSize = 9; // 2 units of padding on either side
|
||||
// of the 7x7 unit checkmark
|
||||
|
||||
// Scale the checkmark based on the smallest dimension
|
||||
nscoord paintScale = std::min(rect.width, rect.height) / checkSize;
|
||||
nsPoint paintCenter(rect.x + rect.width / 2,
|
||||
rect.y + rect.height / 2);
|
||||
|
||||
RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
|
||||
nsPoint p = paintCenter + nsPoint(checkPolygonX[0] * paintScale,
|
||||
checkPolygonY[0] * paintScale);
|
||||
|
||||
int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
builder->MoveTo(NSPointToPoint(p, appUnitsPerDevPixel));
|
||||
for (int32_t polyIndex = 1; polyIndex < checkNumPoints; polyIndex++) {
|
||||
p = paintCenter + nsPoint(checkPolygonX[polyIndex] * paintScale,
|
||||
checkPolygonY[polyIndex] * paintScale);
|
||||
builder->LineTo(NSPointToPoint(p, appUnitsPerDevPixel));
|
||||
}
|
||||
RefPtr<Path> path = builder->Finish();
|
||||
aDrawTarget->Fill(path,
|
||||
ColorPattern(ToDeviceColor(aFrame->StyleColor()->mColor)));
|
||||
}
|
||||
|
||||
static void
|
||||
PaintIndeterminateMark(nsIFrame* aFrame,
|
||||
DrawTarget* aDrawTarget,
|
||||
const nsRect& aDirtyRect,
|
||||
nsPoint aPt)
|
||||
{
|
||||
int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
|
||||
nsRect rect(aPt, aFrame->GetSize());
|
||||
rect.Deflate(aFrame->GetUsedBorderAndPadding());
|
||||
rect.y += (rect.height - rect.height/4) / 2;
|
||||
rect.height /= 4;
|
||||
|
||||
Rect devPxRect = NSRectToSnappedRect(rect, appUnitsPerDevPixel, *aDrawTarget);
|
||||
|
||||
aDrawTarget->FillRect(
|
||||
devPxRect, ColorPattern(ToDeviceColor(aFrame->StyleColor()->mColor)));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
nsIFrame*
|
||||
NS_NewGfxCheckboxControlFrame(nsIPresShell* aPresShell,
|
||||
nsStyleContext* aContext)
|
||||
{
|
||||
return new (aPresShell) nsGfxCheckboxControlFrame(aContext);
|
||||
}
|
||||
|
||||
NS_IMPL_FRAMEARENA_HELPERS(nsGfxCheckboxControlFrame)
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Initialize GFX-rendered state
|
||||
nsGfxCheckboxControlFrame::nsGfxCheckboxControlFrame(nsStyleContext* aContext)
|
||||
: nsFormControlFrame(aContext)
|
||||
{
|
||||
}
|
||||
|
||||
nsGfxCheckboxControlFrame::~nsGfxCheckboxControlFrame()
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
a11y::AccType
|
||||
nsGfxCheckboxControlFrame::AccessibleType()
|
||||
{
|
||||
return a11y::eHTMLCheckboxType;
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------
|
||||
void
|
||||
nsGfxCheckboxControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists)
|
||||
{
|
||||
nsFormControlFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
|
||||
|
||||
// Get current checked state through content model.
|
||||
if ((!IsChecked() && !IsIndeterminate()) || !IsVisibleForPainting(aBuilder))
|
||||
return; // we're not checked or not visible, nothing to paint.
|
||||
|
||||
if (IsThemed())
|
||||
return; // No need to paint the checkmark. The theme will do it.
|
||||
|
||||
aLists.Content()->AppendNewToTop(new (aBuilder)
|
||||
nsDisplayGeneric(aBuilder, this,
|
||||
IsIndeterminate()
|
||||
? PaintIndeterminateMark : PaintCheckMark,
|
||||
"CheckedCheckbox",
|
||||
nsDisplayItem::TYPE_CHECKED_CHECKBOX));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
bool
|
||||
nsGfxCheckboxControlFrame::IsChecked()
|
||||
{
|
||||
nsCOMPtr<nsIDOMHTMLInputElement> elem(do_QueryInterface(mContent));
|
||||
bool retval = false;
|
||||
elem->GetChecked(&retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool
|
||||
nsGfxCheckboxControlFrame::IsIndeterminate()
|
||||
{
|
||||
nsCOMPtr<nsIDOMHTMLInputElement> elem(do_QueryInterface(mContent));
|
||||
bool retval = false;
|
||||
elem->GetIndeterminate(&retval);
|
||||
return retval;
|
||||
}
|
||||
40
layout/forms/nsGfxCheckboxControlFrame.h
Normal file
40
layout/forms/nsGfxCheckboxControlFrame.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef nsGfxCheckboxControlFrame_h___
|
||||
#define nsGfxCheckboxControlFrame_h___
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsFormControlFrame.h"
|
||||
|
||||
class nsGfxCheckboxControlFrame : public nsFormControlFrame
|
||||
{
|
||||
public:
|
||||
NS_DECL_FRAMEARENA_HELPERS
|
||||
|
||||
explicit nsGfxCheckboxControlFrame(nsStyleContext* aContext);
|
||||
virtual ~nsGfxCheckboxControlFrame();
|
||||
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
virtual nsresult GetFrameName(nsAString& aResult) const override {
|
||||
return MakeFrameName(NS_LITERAL_STRING("CheckboxControl"), aResult);
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists) override;
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
virtual mozilla::a11y::AccType AccessibleType() override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
bool IsChecked();
|
||||
bool IsIndeterminate();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
93
layout/forms/nsGfxRadioControlFrame.cpp
Normal file
93
layout/forms/nsGfxRadioControlFrame.cpp
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsGfxRadioControlFrame.h"
|
||||
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxUtils.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/PathHelpers.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsRenderingContext.h"
|
||||
#include "nsDisplayList.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
nsIFrame*
|
||||
NS_NewGfxRadioControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
|
||||
{
|
||||
return new (aPresShell) nsGfxRadioControlFrame(aContext);
|
||||
}
|
||||
|
||||
NS_IMPL_FRAMEARENA_HELPERS(nsGfxRadioControlFrame)
|
||||
|
||||
nsGfxRadioControlFrame::nsGfxRadioControlFrame(nsStyleContext* aContext):
|
||||
nsFormControlFrame(aContext)
|
||||
{
|
||||
}
|
||||
|
||||
nsGfxRadioControlFrame::~nsGfxRadioControlFrame()
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
a11y::AccType
|
||||
nsGfxRadioControlFrame::AccessibleType()
|
||||
{
|
||||
return a11y::eHTMLRadioButtonType;
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// Draw the dot for a non-native radio button in the checked state.
|
||||
static void
|
||||
PaintCheckedRadioButton(nsIFrame* aFrame,
|
||||
DrawTarget* aDrawTarget,
|
||||
const nsRect& aDirtyRect,
|
||||
nsPoint aPt)
|
||||
{
|
||||
// The dot is an ellipse 2px on all sides smaller than the content-box,
|
||||
// drawn in the foreground color.
|
||||
nsRect rect(aPt, aFrame->GetSize());
|
||||
rect.Deflate(aFrame->GetUsedBorderAndPadding());
|
||||
rect.Deflate(nsPresContext::CSSPixelsToAppUnits(2),
|
||||
nsPresContext::CSSPixelsToAppUnits(2));
|
||||
|
||||
Rect devPxRect =
|
||||
ToRect(nsLayoutUtils::RectToGfxRect(rect,
|
||||
aFrame->PresContext()->AppUnitsPerDevPixel()));
|
||||
|
||||
ColorPattern color(ToDeviceColor(aFrame->StyleColor()->mColor));
|
||||
|
||||
RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
|
||||
AppendEllipseToPath(builder, devPxRect.Center(), devPxRect.Size());
|
||||
RefPtr<Path> ellipse = builder->Finish();
|
||||
aDrawTarget->Fill(ellipse, color);
|
||||
}
|
||||
|
||||
void
|
||||
nsGfxRadioControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists)
|
||||
{
|
||||
nsFormControlFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
|
||||
|
||||
if (!IsVisibleForPainting(aBuilder))
|
||||
return;
|
||||
|
||||
if (IsThemed())
|
||||
return; // The theme will paint the check, if any.
|
||||
|
||||
bool checked = true;
|
||||
GetCurrentCheckState(&checked); // Get check state from the content model
|
||||
if (!checked)
|
||||
return;
|
||||
|
||||
aLists.Content()->AppendNewToTop(new (aBuilder)
|
||||
nsDisplayGeneric(aBuilder, this, PaintCheckedRadioButton,
|
||||
"CheckedRadioButton",
|
||||
nsDisplayItem::TYPE_CHECKED_RADIOBUTTON));
|
||||
}
|
||||
32
layout/forms/nsGfxRadioControlFrame.h
Normal file
32
layout/forms/nsGfxRadioControlFrame.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsGfxRadioControlFrame_h___
|
||||
#define nsGfxRadioControlFrame_h___
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsFormControlFrame.h"
|
||||
|
||||
|
||||
// nsGfxRadioControlFrame
|
||||
|
||||
class nsGfxRadioControlFrame : public nsFormControlFrame
|
||||
{
|
||||
public:
|
||||
explicit nsGfxRadioControlFrame(nsStyleContext* aContext);
|
||||
~nsGfxRadioControlFrame();
|
||||
|
||||
NS_DECL_FRAMEARENA_HELPERS
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
virtual mozilla::a11y::AccType AccessibleType() override;
|
||||
#endif
|
||||
|
||||
virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
465
layout/forms/nsHTMLButtonControlFrame.cpp
Normal file
465
layout/forms/nsHTMLButtonControlFrame.cpp
Normal file
|
|
@ -0,0 +1,465 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsHTMLButtonControlFrame.h"
|
||||
|
||||
#include "nsContainerFrame.h"
|
||||
#include "nsIFormControlFrame.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsButtonFrameRenderer.h"
|
||||
#include "nsCSSAnonBoxes.h"
|
||||
#include "nsFormControlFrame.h"
|
||||
#include "nsNameSpaceManager.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
nsContainerFrame*
|
||||
NS_NewHTMLButtonControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
|
||||
{
|
||||
return new (aPresShell) nsHTMLButtonControlFrame(aContext);
|
||||
}
|
||||
|
||||
NS_IMPL_FRAMEARENA_HELPERS(nsHTMLButtonControlFrame)
|
||||
|
||||
nsHTMLButtonControlFrame::nsHTMLButtonControlFrame(nsStyleContext* aContext)
|
||||
: nsContainerFrame(aContext)
|
||||
{
|
||||
}
|
||||
|
||||
nsHTMLButtonControlFrame::~nsHTMLButtonControlFrame()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLButtonControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
|
||||
{
|
||||
nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false);
|
||||
nsContainerFrame::DestroyFrom(aDestructRoot);
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLButtonControlFrame::Init(nsIContent* aContent,
|
||||
nsContainerFrame* aParent,
|
||||
nsIFrame* aPrevInFlow)
|
||||
{
|
||||
nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
|
||||
mRenderer.SetFrame(this, PresContext());
|
||||
}
|
||||
|
||||
NS_QUERYFRAME_HEAD(nsHTMLButtonControlFrame)
|
||||
NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
|
||||
NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
a11y::AccType
|
||||
nsHTMLButtonControlFrame::AccessibleType()
|
||||
{
|
||||
return a11y::eHTMLButtonType;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsIAtom*
|
||||
nsHTMLButtonControlFrame::GetType() const
|
||||
{
|
||||
return nsGkAtoms::HTMLButtonControlFrame;
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLButtonControlFrame::SetFocus(bool aOn, bool aRepaint)
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLButtonControlFrame::HandleEvent(nsPresContext* aPresContext,
|
||||
WidgetGUIEvent* aEvent,
|
||||
nsEventStatus* aEventStatus)
|
||||
{
|
||||
// if disabled do nothing
|
||||
if (mRenderer.isDisabled()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// mouse clicks are handled by content
|
||||
// we don't want our children to get any events. So just pass it to frame.
|
||||
return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
|
||||
}
|
||||
|
||||
bool
|
||||
nsHTMLButtonControlFrame::ShouldClipPaintingToBorderBox()
|
||||
{
|
||||
return IsInput() || StyleDisplay()->mOverflowX != NS_STYLE_OVERFLOW_VISIBLE;
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLButtonControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists)
|
||||
{
|
||||
// Clip to our border area for event hit testing.
|
||||
Maybe<DisplayListClipState::AutoSaveRestore> eventClipState;
|
||||
const bool isForEventDelivery = aBuilder->IsForEventDelivery();
|
||||
if (isForEventDelivery) {
|
||||
eventClipState.emplace(aBuilder);
|
||||
nsRect rect(aBuilder->ToReferenceFrame(this), GetSize());
|
||||
nscoord radii[8];
|
||||
bool hasRadii = GetBorderRadii(radii);
|
||||
eventClipState->ClipContainingBlockDescendants(rect, hasRadii ? radii : nullptr);
|
||||
}
|
||||
|
||||
nsDisplayList onTop;
|
||||
if (IsVisibleForPainting(aBuilder)) {
|
||||
mRenderer.DisplayButton(aBuilder, aLists.BorderBackground(), &onTop);
|
||||
}
|
||||
|
||||
nsDisplayListCollection set;
|
||||
|
||||
// Do not allow the child subtree to receive events.
|
||||
if (!isForEventDelivery) {
|
||||
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
|
||||
|
||||
if (ShouldClipPaintingToBorderBox()) {
|
||||
nsMargin border = StyleBorder()->GetComputedBorder();
|
||||
nsRect rect(aBuilder->ToReferenceFrame(this), GetSize());
|
||||
rect.Deflate(border);
|
||||
nscoord radii[8];
|
||||
bool hasRadii = GetPaddingBoxBorderRadii(radii);
|
||||
clipState.ClipContainingBlockDescendants(rect, hasRadii ? radii : nullptr);
|
||||
}
|
||||
|
||||
BuildDisplayListForChild(aBuilder, mFrames.FirstChild(), aDirtyRect, set,
|
||||
DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT);
|
||||
// That should put the display items in set.Content()
|
||||
}
|
||||
|
||||
// Put the foreground outline and focus rects on top of the children
|
||||
set.Content()->AppendToTop(&onTop);
|
||||
set.MoveTo(aLists);
|
||||
|
||||
DisplayOutline(aBuilder, aLists);
|
||||
|
||||
// to draw border when selected in editor
|
||||
DisplaySelectionOverlay(aBuilder, aLists.Content());
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsHTMLButtonControlFrame::GetMinISize(nsRenderingContext* aRenderingContext)
|
||||
{
|
||||
nscoord result;
|
||||
DISPLAY_MIN_WIDTH(this, result);
|
||||
|
||||
nsIFrame* kid = mFrames.FirstChild();
|
||||
result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
|
||||
kid,
|
||||
nsLayoutUtils::MIN_ISIZE);
|
||||
|
||||
result += GetWritingMode().IsVertical()
|
||||
? mRenderer.GetAddedButtonBorderAndPadding().TopBottom()
|
||||
: mRenderer.GetAddedButtonBorderAndPadding().LeftRight();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsHTMLButtonControlFrame::GetPrefISize(nsRenderingContext* aRenderingContext)
|
||||
{
|
||||
nscoord result;
|
||||
DISPLAY_PREF_WIDTH(this, result);
|
||||
|
||||
nsIFrame* kid = mFrames.FirstChild();
|
||||
result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
|
||||
kid,
|
||||
nsLayoutUtils::PREF_ISIZE);
|
||||
|
||||
result += GetWritingMode().IsVertical()
|
||||
? mRenderer.GetAddedButtonBorderAndPadding().TopBottom()
|
||||
: mRenderer.GetAddedButtonBorderAndPadding().LeftRight();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLButtonControlFrame::Reflow(nsPresContext* aPresContext,
|
||||
ReflowOutput& aDesiredSize,
|
||||
const ReflowInput& aReflowInput,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
MarkInReflow();
|
||||
DO_GLOBAL_REFLOW_COUNT("nsHTMLButtonControlFrame");
|
||||
DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
|
||||
|
||||
NS_PRECONDITION(aReflowInput.ComputedISize() != NS_INTRINSICSIZE,
|
||||
"Should have real computed inline-size by now");
|
||||
|
||||
if (mState & NS_FRAME_FIRST_REFLOW) {
|
||||
nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), true);
|
||||
}
|
||||
|
||||
// Reflow the child
|
||||
nsIFrame* firstKid = mFrames.FirstChild();
|
||||
|
||||
MOZ_ASSERT(firstKid, "Button should have a child frame for its contents");
|
||||
MOZ_ASSERT(!firstKid->GetNextSibling(),
|
||||
"Button should have exactly one child frame");
|
||||
MOZ_ASSERT(firstKid->StyleContext()->GetPseudo() ==
|
||||
nsCSSAnonBoxes::buttonContent,
|
||||
"Button's child frame has unexpected pseudo type!");
|
||||
|
||||
// XXXbz Eventually we may want to check-and-bail if
|
||||
// !aReflowInput.ShouldReflowAllKids() &&
|
||||
// !NS_SUBTREE_DIRTY(firstKid).
|
||||
// We'd need to cache our ascent for that, of course.
|
||||
|
||||
// Reflow the contents of the button.
|
||||
// (This populates our aDesiredSize, too.)
|
||||
ReflowButtonContents(aPresContext, aDesiredSize,
|
||||
aReflowInput, firstKid);
|
||||
|
||||
if (!ShouldClipPaintingToBorderBox()) {
|
||||
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, firstKid);
|
||||
}
|
||||
// else, we ignore child overflow -- anything that overflows beyond our
|
||||
// own border-box will get clipped when painting.
|
||||
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize,
|
||||
aReflowInput, aStatus);
|
||||
|
||||
// We're always complete and we don't support overflow containers
|
||||
// so we shouldn't have a next-in-flow ever.
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
MOZ_ASSERT(!GetNextInFlow());
|
||||
|
||||
NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
|
||||
}
|
||||
|
||||
// Helper-function that lets us clone the button's reflow state, but with its
|
||||
// ComputedWidth and ComputedHeight reduced by the amount of renderer-specific
|
||||
// focus border and padding that we're using. (This lets us provide a more
|
||||
// appropriate content-box size for descendents' percent sizes to resolve
|
||||
// against.)
|
||||
static ReflowInput
|
||||
CloneReflowInputWithReducedContentBox(
|
||||
const ReflowInput& aButtonReflowInput,
|
||||
const nsMargin& aFocusPadding)
|
||||
{
|
||||
nscoord adjustedWidth =
|
||||
aButtonReflowInput.ComputedWidth() - aFocusPadding.LeftRight();
|
||||
adjustedWidth = std::max(0, adjustedWidth);
|
||||
|
||||
// (Only adjust height if it's an actual length.)
|
||||
nscoord adjustedHeight = aButtonReflowInput.ComputedHeight();
|
||||
if (adjustedHeight != NS_INTRINSICSIZE) {
|
||||
adjustedHeight -= aFocusPadding.TopBottom();
|
||||
adjustedHeight = std::max(0, adjustedHeight);
|
||||
}
|
||||
|
||||
ReflowInput clone(aButtonReflowInput);
|
||||
clone.SetComputedWidth(adjustedWidth);
|
||||
clone.SetComputedHeight(adjustedHeight);
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLButtonControlFrame::ReflowButtonContents(nsPresContext* aPresContext,
|
||||
ReflowOutput& aButtonDesiredSize,
|
||||
const ReflowInput& aButtonReflowInput,
|
||||
nsIFrame* aFirstKid)
|
||||
{
|
||||
WritingMode wm = GetWritingMode();
|
||||
LogicalSize availSize = aButtonReflowInput.ComputedSize(wm);
|
||||
availSize.BSize(wm) = NS_INTRINSICSIZE;
|
||||
|
||||
// Buttons have some bonus renderer-determined border/padding,
|
||||
// which occupies part of the button's content-box area:
|
||||
LogicalMargin focusPadding =
|
||||
LogicalMargin(wm, mRenderer.GetAddedButtonBorderAndPadding());
|
||||
|
||||
// See whether out availSize's inline-size is big enough. If it's
|
||||
// smaller than our intrinsic min iSize, that means that the kid
|
||||
// wouldn't really fit. In that case, we overflow into our internal
|
||||
// focuspadding (which other browsers don't have) so that there's a
|
||||
// little more space for it.
|
||||
// Note that GetMinISize includes the focusPadding.
|
||||
nscoord IOverflow = GetMinISize(aButtonReflowInput.mRenderingContext) -
|
||||
aButtonReflowInput.ComputedISize();
|
||||
nscoord IFocusPadding = focusPadding.IStartEnd(wm);
|
||||
nscoord focusPaddingReduction = std::min(IFocusPadding,
|
||||
std::max(IOverflow, 0));
|
||||
if (focusPaddingReduction > 0) {
|
||||
nscoord startReduction = focusPadding.IStart(wm);
|
||||
if (focusPaddingReduction != IFocusPadding) {
|
||||
startReduction = NSToCoordRound(startReduction *
|
||||
(float(focusPaddingReduction) /
|
||||
float(IFocusPadding)));
|
||||
}
|
||||
focusPadding.IStart(wm) -= startReduction;
|
||||
focusPadding.IEnd(wm) -= focusPaddingReduction - startReduction;
|
||||
}
|
||||
|
||||
// shorthand for a value we need to use in a bunch of places
|
||||
const LogicalMargin& clbp = aButtonReflowInput.ComputedLogicalBorderPadding();
|
||||
|
||||
// Indent the child inside us by the focus border. We must do this separate
|
||||
// from the regular border.
|
||||
availSize.ISize(wm) -= focusPadding.IStartEnd(wm);
|
||||
|
||||
LogicalPoint childPos(wm);
|
||||
childPos.I(wm) = focusPadding.IStart(wm) + clbp.IStart(wm);
|
||||
availSize.ISize(wm) = std::max(availSize.ISize(wm), 0);
|
||||
|
||||
// Give child a clone of the button's reflow state, with height/width reduced
|
||||
// by focusPadding, so that descendants with height:100% don't protrude.
|
||||
ReflowInput adjustedButtonReflowInput =
|
||||
CloneReflowInputWithReducedContentBox(aButtonReflowInput,
|
||||
focusPadding.GetPhysicalMargin(wm));
|
||||
|
||||
ReflowInput contentsReflowInput(aPresContext,
|
||||
adjustedButtonReflowInput,
|
||||
aFirstKid, availSize);
|
||||
|
||||
nsReflowStatus contentsReflowStatus;
|
||||
ReflowOutput contentsDesiredSize(aButtonReflowInput);
|
||||
childPos.B(wm) = 0; // This will be set properly later, after reflowing the
|
||||
// child to determine its size.
|
||||
|
||||
// We just pass a dummy containerSize here, as the child will be
|
||||
// repositioned later by FinishReflowChild.
|
||||
nsSize dummyContainerSize;
|
||||
ReflowChild(aFirstKid, aPresContext,
|
||||
contentsDesiredSize, contentsReflowInput,
|
||||
wm, childPos, dummyContainerSize, 0, contentsReflowStatus);
|
||||
MOZ_ASSERT(NS_FRAME_IS_COMPLETE(contentsReflowStatus),
|
||||
"We gave button-contents frame unconstrained available height, "
|
||||
"so it should be complete");
|
||||
|
||||
// Compute the button's content-box size:
|
||||
LogicalSize buttonContentBox(wm);
|
||||
if (aButtonReflowInput.ComputedBSize() != NS_INTRINSICSIZE) {
|
||||
// Button has a fixed block-size -- that's its content-box bSize.
|
||||
buttonContentBox.BSize(wm) = aButtonReflowInput.ComputedBSize();
|
||||
} else {
|
||||
// Button is intrinsically sized -- it should shrinkwrap the
|
||||
// button-contents' bSize, plus any focus-padding space:
|
||||
buttonContentBox.BSize(wm) =
|
||||
contentsDesiredSize.BSize(wm) + focusPadding.BStartEnd(wm);
|
||||
|
||||
// Make sure we obey min/max-bSize in the case when we're doing intrinsic
|
||||
// sizing (we get it for free when we have a non-intrinsic
|
||||
// aButtonReflowInput.ComputedBSize()). Note that we do this before
|
||||
// adjusting for borderpadding, since mComputedMaxBSize and
|
||||
// mComputedMinBSize are content bSizes.
|
||||
buttonContentBox.BSize(wm) =
|
||||
NS_CSS_MINMAX(buttonContentBox.BSize(wm),
|
||||
aButtonReflowInput.ComputedMinBSize(),
|
||||
aButtonReflowInput.ComputedMaxBSize());
|
||||
}
|
||||
if (aButtonReflowInput.ComputedISize() != NS_INTRINSICSIZE) {
|
||||
buttonContentBox.ISize(wm) = aButtonReflowInput.ComputedISize();
|
||||
} else {
|
||||
buttonContentBox.ISize(wm) =
|
||||
contentsDesiredSize.ISize(wm) + focusPadding.IStartEnd(wm);
|
||||
buttonContentBox.ISize(wm) =
|
||||
NS_CSS_MINMAX(buttonContentBox.ISize(wm),
|
||||
aButtonReflowInput.ComputedMinISize(),
|
||||
aButtonReflowInput.ComputedMaxISize());
|
||||
}
|
||||
|
||||
// Center child in the block-direction in the button
|
||||
// (technically, inside of the button's focus-padding area)
|
||||
nscoord extraSpace =
|
||||
buttonContentBox.BSize(wm) - focusPadding.BStartEnd(wm) -
|
||||
contentsDesiredSize.BSize(wm);
|
||||
|
||||
childPos.B(wm) = std::max(0, extraSpace / 2);
|
||||
|
||||
// Adjust childPos.B() to be in terms of the button's frame-rect, instead of
|
||||
// its focus-padding rect:
|
||||
childPos.B(wm) += focusPadding.BStart(wm) + clbp.BStart(wm);
|
||||
|
||||
nsSize containerSize =
|
||||
(buttonContentBox + clbp.Size(wm)).GetPhysicalSize(wm);
|
||||
|
||||
// Place the child
|
||||
FinishReflowChild(aFirstKid, aPresContext,
|
||||
contentsDesiredSize, &contentsReflowInput,
|
||||
wm, childPos, containerSize, 0);
|
||||
|
||||
// Make sure we have a useful 'ascent' value for the child
|
||||
if (contentsDesiredSize.BlockStartAscent() ==
|
||||
ReflowOutput::ASK_FOR_BASELINE) {
|
||||
WritingMode wm = aButtonReflowInput.GetWritingMode();
|
||||
contentsDesiredSize.SetBlockStartAscent(aFirstKid->GetLogicalBaseline(wm));
|
||||
}
|
||||
|
||||
// OK, we're done with the child frame.
|
||||
// Use what we learned to populate the button frame's reflow metrics.
|
||||
// * Button's height & width are content-box size + border-box contribution:
|
||||
aButtonDesiredSize.SetSize(wm,
|
||||
LogicalSize(wm, aButtonReflowInput.ComputedISize() + clbp.IStartEnd(wm),
|
||||
buttonContentBox.BSize(wm) + clbp.BStartEnd(wm)));
|
||||
|
||||
// * Button's ascent is its child's ascent, plus the child's block-offset
|
||||
// within our frame... unless it's orthogonal, in which case we'll use the
|
||||
// contents inline-size as an approximation for now.
|
||||
// XXX is there a better strategy? should we include border-padding?
|
||||
if (aButtonDesiredSize.GetWritingMode().IsOrthogonalTo(wm)) {
|
||||
aButtonDesiredSize.SetBlockStartAscent(contentsDesiredSize.ISize(wm));
|
||||
} else {
|
||||
aButtonDesiredSize.SetBlockStartAscent(contentsDesiredSize.BlockStartAscent() +
|
||||
childPos.B(wm));
|
||||
}
|
||||
|
||||
aButtonDesiredSize.SetOverflowAreasToDesiredBounds();
|
||||
}
|
||||
|
||||
nsresult nsHTMLButtonControlFrame::SetFormProperty(nsIAtom* aName, const nsAString& aValue)
|
||||
{
|
||||
if (nsGkAtoms::value == aName) {
|
||||
return mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::value,
|
||||
aValue, true);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsStyleContext*
|
||||
nsHTMLButtonControlFrame::GetAdditionalStyleContext(int32_t aIndex) const
|
||||
{
|
||||
return mRenderer.GetStyleContext(aIndex);
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLButtonControlFrame::SetAdditionalStyleContext(int32_t aIndex,
|
||||
nsStyleContext* aStyleContext)
|
||||
{
|
||||
mRenderer.SetStyleContext(aIndex, aStyleContext);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
nsHTMLButtonControlFrame::AppendFrames(ChildListID aListID,
|
||||
nsFrameList& aFrameList)
|
||||
{
|
||||
MOZ_CRASH("unsupported operation");
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLButtonControlFrame::InsertFrames(ChildListID aListID,
|
||||
nsIFrame* aPrevFrame,
|
||||
nsFrameList& aFrameList)
|
||||
{
|
||||
MOZ_CRASH("unsupported operation");
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLButtonControlFrame::RemoveFrame(ChildListID aListID,
|
||||
nsIFrame* aOldFrame)
|
||||
{
|
||||
MOZ_CRASH("unsupported operation");
|
||||
}
|
||||
#endif
|
||||
115
layout/forms/nsHTMLButtonControlFrame.h
Normal file
115
layout/forms/nsHTMLButtonControlFrame.h
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsHTMLButtonControlFrame_h___
|
||||
#define nsHTMLButtonControlFrame_h___
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsContainerFrame.h"
|
||||
#include "nsIFormControlFrame.h"
|
||||
#include "nsButtonFrameRenderer.h"
|
||||
|
||||
class nsRenderingContext;
|
||||
class nsPresContext;
|
||||
|
||||
class nsHTMLButtonControlFrame : public nsContainerFrame,
|
||||
public nsIFormControlFrame
|
||||
{
|
||||
public:
|
||||
explicit nsHTMLButtonControlFrame(nsStyleContext* aContext);
|
||||
~nsHTMLButtonControlFrame();
|
||||
|
||||
virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
|
||||
|
||||
NS_DECL_QUERYFRAME
|
||||
NS_DECL_FRAMEARENA_HELPERS
|
||||
|
||||
virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists) override;
|
||||
|
||||
virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) override;
|
||||
|
||||
virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext) override;
|
||||
|
||||
virtual void Reflow(nsPresContext* aPresContext,
|
||||
ReflowOutput& aDesiredSize,
|
||||
const ReflowInput& aReflowInput,
|
||||
nsReflowStatus& aStatus) override;
|
||||
|
||||
virtual nsresult HandleEvent(nsPresContext* aPresContext,
|
||||
mozilla::WidgetGUIEvent* aEvent,
|
||||
nsEventStatus* aEventStatus) override;
|
||||
|
||||
virtual void Init(nsIContent* aContent,
|
||||
nsContainerFrame* aParent,
|
||||
nsIFrame* aPrevInFlow) override;
|
||||
|
||||
virtual nsStyleContext* GetAdditionalStyleContext(int32_t aIndex) const override;
|
||||
virtual void SetAdditionalStyleContext(int32_t aIndex,
|
||||
nsStyleContext* aStyleContext) override;
|
||||
|
||||
#ifdef DEBUG
|
||||
virtual void AppendFrames(ChildListID aListID,
|
||||
nsFrameList& aFrameList) override;
|
||||
virtual void InsertFrames(ChildListID aListID,
|
||||
nsIFrame* aPrevFrame,
|
||||
nsFrameList& aFrameList) override;
|
||||
virtual void RemoveFrame(ChildListID aListID,
|
||||
nsIFrame* aOldFrame) override;
|
||||
#endif
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
virtual mozilla::a11y::AccType AccessibleType() override;
|
||||
#endif
|
||||
|
||||
virtual nsIAtom* GetType() const override;
|
||||
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
virtual nsresult GetFrameName(nsAString& aResult) const override {
|
||||
return MakeFrameName(NS_LITERAL_STRING("HTMLButtonControl"), aResult);
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual bool HonorPrintBackgroundSettings() override { return false; }
|
||||
|
||||
// nsIFormControlFrame
|
||||
void SetFocus(bool aOn, bool aRepaint) override;
|
||||
virtual nsresult SetFormProperty(nsIAtom* aName, const nsAString& aValue) override;
|
||||
|
||||
// Inserted child content gets its frames parented by our child block
|
||||
virtual nsContainerFrame* GetContentInsertionFrame() override {
|
||||
return PrincipalChildList().FirstChild()->GetContentInsertionFrame();
|
||||
}
|
||||
|
||||
virtual bool IsFrameOfType(uint32_t aFlags) const override
|
||||
{
|
||||
return nsContainerFrame::IsFrameOfType(aFlags &
|
||||
~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool IsInput() { return false; }
|
||||
|
||||
// Indicates whether we should clip our children's painting to our
|
||||
// border-box (either because of "overflow" or because of legacy reasons
|
||||
// about how <input>-flavored buttons work).
|
||||
bool ShouldClipPaintingToBorderBox();
|
||||
|
||||
// Reflows the button's sole child frame, and computes the desired size
|
||||
// of the button itself from the results.
|
||||
void ReflowButtonContents(nsPresContext* aPresContext,
|
||||
ReflowOutput& aButtonDesiredSize,
|
||||
const ReflowInput& aButtonReflowInput,
|
||||
nsIFrame* aFirstKid);
|
||||
|
||||
nsButtonFrameRenderer mRenderer;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
86
layout/forms/nsIComboboxControlFrame.h
Normal file
86
layout/forms/nsIComboboxControlFrame.h
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsIComboboxControlFrame_h___
|
||||
#define nsIComboboxControlFrame_h___
|
||||
|
||||
#include "nsQueryFrame.h"
|
||||
|
||||
/**
|
||||
* nsIComboboxControlFrame is the interface for comboboxes.
|
||||
*/
|
||||
class nsIComboboxControlFrame : public nsQueryFrame
|
||||
{
|
||||
public:
|
||||
NS_DECL_QUERYFRAME_TARGET(nsIComboboxControlFrame)
|
||||
|
||||
/**
|
||||
* Indicates whether the list is dropped down
|
||||
*/
|
||||
virtual bool IsDroppedDown() = 0;
|
||||
|
||||
virtual bool IsOpenInParentProcess() = 0;
|
||||
virtual void SetOpenInParentProcess(bool aVal) = 0;
|
||||
|
||||
bool IsDroppedDownOrHasParentPopup() { return IsDroppedDown() || IsOpenInParentProcess(); }
|
||||
|
||||
/**
|
||||
* Shows or hides the drop down
|
||||
*/
|
||||
virtual void ShowDropDown(bool aDoDropDown) = 0;
|
||||
|
||||
/**
|
||||
* Gets the Drop Down List
|
||||
*/
|
||||
virtual nsIFrame* GetDropDown() = 0;
|
||||
|
||||
/**
|
||||
* Sets the Drop Down List
|
||||
*/
|
||||
virtual void SetDropDown(nsIFrame* aDropDownFrame) = 0;
|
||||
|
||||
/**
|
||||
* Tells the combobox to roll up
|
||||
*/
|
||||
virtual void RollupFromList() = 0;
|
||||
|
||||
/**
|
||||
* Redisplay the selected text (will do nothing if text has not changed).
|
||||
* This method might destroy this frame or any others that happen to be
|
||||
* around. It might even run script.
|
||||
*/
|
||||
NS_IMETHOD RedisplaySelectedText() = 0;
|
||||
|
||||
/**
|
||||
* Method for the listbox to set and get the recent index
|
||||
*/
|
||||
virtual int32_t UpdateRecentIndex(int32_t aIndex) = 0;
|
||||
|
||||
/**
|
||||
* Notification that the content has been reset
|
||||
*/
|
||||
virtual void OnContentReset() = 0;
|
||||
|
||||
/**
|
||||
* This returns the index of the item that is currently being displayed
|
||||
* in the display area. It may differ from what the currently Selected index
|
||||
* is in in the dropdown.
|
||||
*
|
||||
* Detailed explanation:
|
||||
* When the dropdown is dropped down via a mouse click and the user moves the mouse
|
||||
* up and down without clicking, the currently selected item is being tracking inside
|
||||
* the dropdown, but the combobox is not being updated. When the user selects items
|
||||
* with the arrow keys, the combobox is being updated. So when the user clicks outside
|
||||
* the dropdown and it needs to roll up it has to decide whether to keep the current
|
||||
* selection or not. This method is used to get the current index in the combobox to
|
||||
* compare it to the current index in the dropdown to see if the combox has been updated
|
||||
* and that way it knows whether to "cancel" the current selection residing in the
|
||||
* dropdown. Or whether to leave the selection alone.
|
||||
*/
|
||||
virtual int32_t GetIndexOfDisplayArea() = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
42
layout/forms/nsIFormControlFrame.h
Normal file
42
layout/forms/nsIFormControlFrame.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsIFormControlFrame_h___
|
||||
#define nsIFormControlFrame_h___
|
||||
|
||||
#include "nsQueryFrame.h"
|
||||
|
||||
class nsAString;
|
||||
class nsIAtom;
|
||||
|
||||
/**
|
||||
* nsIFormControlFrame is the common interface for frames of form controls. It
|
||||
* provides a uniform way of creating widgets, resizing, and painting.
|
||||
* @see nsLeafFrame and its base classes for more info
|
||||
*/
|
||||
class nsIFormControlFrame : public nsQueryFrame
|
||||
{
|
||||
public:
|
||||
NS_DECL_QUERYFRAME_TARGET(nsIFormControlFrame)
|
||||
|
||||
/**
|
||||
*
|
||||
* @param aOn
|
||||
* @param aRepaint
|
||||
*/
|
||||
virtual void SetFocus(bool aOn = true, bool aRepaint = false) = 0;
|
||||
|
||||
/**
|
||||
* Set a property on the form control frame.
|
||||
*
|
||||
* @param aName name of the property to set
|
||||
* @param aValue value of the property
|
||||
* @returns NS_OK if the property name is valid, otherwise an error code
|
||||
*/
|
||||
virtual nsresult SetFormProperty(nsIAtom* aName, const nsAString& aValue) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
98
layout/forms/nsIListControlFrame.h
Normal file
98
layout/forms/nsIListControlFrame.h
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsIListControlFrame_h___
|
||||
#define nsIListControlFrame_h___
|
||||
|
||||
#include "nsQueryFrame.h"
|
||||
|
||||
class nsAString;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class HTMLOptionElement;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
/**
|
||||
* nsIListControlFrame is the interface for frame-based listboxes.
|
||||
*/
|
||||
class nsIListControlFrame : public nsQueryFrame
|
||||
{
|
||||
public:
|
||||
NS_DECL_QUERYFRAME_TARGET(nsIListControlFrame)
|
||||
|
||||
/**
|
||||
* Sets the ComboBoxFrame
|
||||
*
|
||||
*/
|
||||
virtual void SetComboboxFrame(nsIFrame* aComboboxFrame) = 0;
|
||||
|
||||
/**
|
||||
* Get the display string for an item
|
||||
*/
|
||||
virtual void GetOptionText(uint32_t aIndex, nsAString& aStr) = 0;
|
||||
|
||||
/**
|
||||
* Get the Selected Item's index
|
||||
*
|
||||
*/
|
||||
virtual int32_t GetSelectedIndex() = 0;
|
||||
|
||||
/**
|
||||
* Return current option. The current option is the option displaying
|
||||
* the focus ring when the listbox is focused.
|
||||
*/
|
||||
virtual mozilla::dom::HTMLOptionElement* GetCurrentOption() = 0;
|
||||
|
||||
/**
|
||||
* Initiates mouse capture for the listbox
|
||||
*
|
||||
*/
|
||||
virtual void CaptureMouseEvents(bool aGrabMouseEvents) = 0;
|
||||
|
||||
/**
|
||||
* Returns the block size of a single row in the list. This is the
|
||||
* maximum of the block sizes of all the options/optgroups.
|
||||
*/
|
||||
virtual nscoord GetBSizeOfARow() = 0;
|
||||
|
||||
/**
|
||||
* Returns the number of options in the listbox
|
||||
*/
|
||||
|
||||
virtual uint32_t GetNumberOfOptions() = 0;
|
||||
|
||||
/**
|
||||
* Called by combobox when it's about to drop down
|
||||
*/
|
||||
virtual void AboutToDropDown() = 0;
|
||||
|
||||
/**
|
||||
* Called by combobox when it's about to roll up
|
||||
*/
|
||||
virtual void AboutToRollup() = 0;
|
||||
|
||||
/**
|
||||
* Fire on input and on change (used by combobox)
|
||||
*/
|
||||
virtual void FireOnInputAndOnChange() = 0;
|
||||
|
||||
/**
|
||||
* Tell the selected list to roll up and ensure that the proper index is
|
||||
* selected, possibly firing onChange if the index has changed
|
||||
*
|
||||
* @param aIndex the index to actually select
|
||||
*/
|
||||
virtual void ComboboxFinish(int32_t aIndex) = 0;
|
||||
|
||||
/**
|
||||
* Notification that the content has been reset
|
||||
*/
|
||||
virtual void OnContentReset() = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
50
layout/forms/nsISelectControlFrame.h
Normal file
50
layout/forms/nsISelectControlFrame.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsISelectControlFrame_h___
|
||||
#define nsISelectControlFrame_h___
|
||||
|
||||
#include "nsQueryFrame.h"
|
||||
|
||||
/**
|
||||
* nsISelectControlFrame is the interface for combo boxes and listboxes
|
||||
*/
|
||||
class nsISelectControlFrame : public nsQueryFrame
|
||||
{
|
||||
public:
|
||||
NS_DECL_QUERYFRAME_TARGET(nsISelectControlFrame)
|
||||
|
||||
/**
|
||||
* Adds an option to the list at index
|
||||
*/
|
||||
|
||||
NS_IMETHOD AddOption(int32_t index) = 0;
|
||||
|
||||
/**
|
||||
* Removes the option at index. The caller must have a live script
|
||||
* blocker while calling this method.
|
||||
*/
|
||||
NS_IMETHOD RemoveOption(int32_t index) = 0;
|
||||
|
||||
/**
|
||||
* Sets whether the parser is done adding children
|
||||
* @param aIsDone whether the parser is done adding children
|
||||
*/
|
||||
NS_IMETHOD DoneAddingChildren(bool aIsDone) = 0;
|
||||
|
||||
/**
|
||||
* Notify the frame when an option is selected
|
||||
*/
|
||||
NS_IMETHOD OnOptionSelected(int32_t aIndex, bool aSelected) = 0;
|
||||
|
||||
/**
|
||||
* Notify the frame when selectedIndex was changed. This might
|
||||
* destroy the frame.
|
||||
*/
|
||||
NS_IMETHOD OnSetSelectedIndex(int32_t aOldIndex, int32_t aNewIndex) = 0;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
53
layout/forms/nsITextControlFrame.h
Normal file
53
layout/forms/nsITextControlFrame.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsITextControlFrame_h___
|
||||
#define nsITextControlFrame_h___
|
||||
|
||||
#include "nsIFormControlFrame.h"
|
||||
|
||||
class nsIEditor;
|
||||
class nsISelectionController;
|
||||
class nsFrameSelection;
|
||||
|
||||
class nsITextControlFrame : public nsIFormControlFrame
|
||||
{
|
||||
public:
|
||||
NS_DECL_QUERYFRAME_TARGET(nsITextControlFrame)
|
||||
|
||||
enum SelectionDirection {
|
||||
eNone,
|
||||
eForward,
|
||||
eBackward
|
||||
};
|
||||
|
||||
NS_IMETHOD GetEditor(nsIEditor **aEditor) = 0;
|
||||
|
||||
NS_IMETHOD SetSelectionStart(int32_t aSelectionStart) = 0;
|
||||
NS_IMETHOD SetSelectionEnd(int32_t aSelectionEnd) = 0;
|
||||
|
||||
NS_IMETHOD SetSelectionRange(int32_t aSelectionStart,
|
||||
int32_t aSelectionEnd,
|
||||
SelectionDirection aDirection = eNone) = 0;
|
||||
NS_IMETHOD GetSelectionRange(int32_t* aSelectionStart,
|
||||
int32_t* aSelectionEnd,
|
||||
SelectionDirection* aDirection = nullptr) = 0;
|
||||
|
||||
NS_IMETHOD GetOwnedSelectionController(nsISelectionController** aSelCon) = 0;
|
||||
virtual nsFrameSelection* GetOwnedFrameSelection() = 0;
|
||||
|
||||
virtual nsresult GetPhonetic(nsAString& aPhonetic) = 0;
|
||||
|
||||
/**
|
||||
* Ensure editor is initialized with the proper flags and the default value.
|
||||
* @throws NS_ERROR_NOT_INITIALIZED if mEditor has not been created
|
||||
* @throws various and sundry other things
|
||||
*/
|
||||
virtual nsresult EnsureEditorInitialized() = 0;
|
||||
|
||||
virtual nsresult ScrollSelectionIntoView() = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue