mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge the last PGO-green inbound changeset to m-c.
This commit is contained in:
commit
81ec2f7d25
@ -74,7 +74,7 @@ private:
|
||||
class EmbeddedObjCollector : public AccCollector
|
||||
{
|
||||
public:
|
||||
virtual ~EmbeddedObjCollector() { };
|
||||
virtual ~EmbeddedObjCollector() { }
|
||||
|
||||
public:
|
||||
virtual int32_t GetIndexAt(Accessible* aAccessible);
|
||||
|
@ -213,7 +213,7 @@ public:
|
||||
mNode = aTargetNode;
|
||||
mParent = mAccessible->Parent();
|
||||
}
|
||||
virtual ~AccMutationEvent() { };
|
||||
virtual ~AccMutationEvent() { }
|
||||
|
||||
// Event
|
||||
static const EventGroup kEventGroup = eMutationEvent;
|
||||
@ -291,7 +291,7 @@ public:
|
||||
AccReorderEvent(Accessible* aTarget) :
|
||||
AccEvent(::nsIAccessibleEvent::EVENT_REORDER, aTarget,
|
||||
eAutoDetect, eCoalesceReorder) { }
|
||||
virtual ~AccReorderEvent() { };
|
||||
virtual ~AccReorderEvent() { }
|
||||
|
||||
// Event
|
||||
static const EventGroup kEventGroup = eReorderEvent;
|
||||
|
@ -28,7 +28,7 @@ class DocAccessible;
|
||||
class Notification
|
||||
{
|
||||
public:
|
||||
virtual ~Notification() { };
|
||||
virtual ~Notification() { }
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(Notification)
|
||||
|
||||
|
@ -17,7 +17,7 @@ class StyleInfo
|
||||
{
|
||||
public:
|
||||
StyleInfo(dom::Element* aElement, nsIPresShell* aPresShell);
|
||||
~StyleInfo() { };
|
||||
~StyleInfo() { }
|
||||
|
||||
void Display(nsAString& aValue);
|
||||
void TextAlign(nsAString& aValue);
|
||||
|
@ -304,8 +304,8 @@ public:
|
||||
class nsAccessibleDOMStringList : public nsIDOMDOMStringList
|
||||
{
|
||||
public:
|
||||
nsAccessibleDOMStringList() {};
|
||||
virtual ~nsAccessibleDOMStringList() {};
|
||||
nsAccessibleDOMStringList() {}
|
||||
virtual ~nsAccessibleDOMStringList() {}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOMDOMSTRINGLIST
|
||||
|
@ -950,7 +950,7 @@ public:
|
||||
|
||||
KeyBinding() : mKey(0), mModifierMask(0) {}
|
||||
KeyBinding(uint32_t aKey, uint32_t aModifierMask) :
|
||||
mKey(aKey), mModifierMask(aModifierMask) {};
|
||||
mKey(aKey), mModifierMask(aModifierMask) {}
|
||||
|
||||
inline bool IsEmpty() const { return !mKey; }
|
||||
inline uint32_t Key() const { return mKey; }
|
||||
|
@ -20,7 +20,7 @@ class HTMLHRAccessible : public LeafAccessible
|
||||
public:
|
||||
|
||||
HTMLHRAccessible(nsIContent* aContent, DocAccessible* aDoc) :
|
||||
LeafAccessible(aContent, aDoc) {};
|
||||
LeafAccessible(aContent, aDoc) {}
|
||||
|
||||
// Accessible
|
||||
virtual a11y::role NativeRole();
|
||||
@ -33,7 +33,7 @@ class HTMLBRAccessible : public LeafAccessible
|
||||
{
|
||||
public:
|
||||
HTMLBRAccessible(nsIContent* aContent, DocAccessible* aDoc) :
|
||||
LeafAccessible(aContent, aDoc) {};
|
||||
LeafAccessible(aContent, aDoc) {}
|
||||
|
||||
// Accessible
|
||||
virtual a11y::role NativeRole();
|
||||
@ -52,7 +52,7 @@ class HTMLLabelAccessible : public HyperTextAccessibleWrap
|
||||
public:
|
||||
|
||||
HTMLLabelAccessible(nsIContent* aContent, DocAccessible* aDoc) :
|
||||
HyperTextAccessibleWrap(aContent, aDoc) {};
|
||||
HyperTextAccessibleWrap(aContent, aDoc) {}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
@ -71,7 +71,7 @@ class HTMLOutputAccessible : public HyperTextAccessibleWrap
|
||||
public:
|
||||
|
||||
HTMLOutputAccessible(nsIContent* aContent, DocAccessible* aDoc) :
|
||||
HyperTextAccessibleWrap(aContent, aDoc) {};
|
||||
HyperTextAccessibleWrap(aContent, aDoc) {}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
|
@ -123,7 +123,6 @@ _BROWSER_FILES = \
|
||||
browser_bug556061.js \
|
||||
browser_bug559991.js \
|
||||
browser_bug561623.js \
|
||||
browser_bug561636.js \
|
||||
browser_bug562649.js \
|
||||
browser_bug563588.js \
|
||||
browser_bug565575.js \
|
||||
@ -314,10 +313,15 @@ else
|
||||
_BROWSER_FILES += \
|
||||
browser_bug565667.js \
|
||||
$(NULL)
|
||||
|
||||
# TODO: Activate after carbon test plugin lands, bug 628651
|
||||
# browser_maconly_carbon_mismatch_plugin.js \
|
||||
# browser_maconly_carbon_mismatch_plugin.js
|
||||
endif
|
||||
|
||||
# bug 766546, disable browser_bug561636.js on Windows
|
||||
ifneq ($(OS_ARCH),WINNT)
|
||||
_BROWSER_FILES += \
|
||||
browser_bug561636.js \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
|
||||
|
@ -12,18 +12,21 @@ relativesrcdir = @relativesrcdir@
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MOCHITEST_BROWSER_FILES = \
|
||||
browser_dbg_cmd_break.html \
|
||||
browser_dbg_cmd_break.js \
|
||||
browser_dbg_cmd.html \
|
||||
browser_dbg_cmd.js \
|
||||
browser_cmd_addon.js \
|
||||
browser_cmd_calllog.js \
|
||||
browser_cmd_calllog_chrome.js \
|
||||
browser_cmd_commands.js \
|
||||
browser_cmd_cookie.js \
|
||||
browser_cmd_integrate.js \
|
||||
browser_cmd_jsb.js \
|
||||
browser_cmd_jsb_script.jsi \
|
||||
browser_cmd_pagemod_export.html \
|
||||
browser_cmd_pagemod_export.js \
|
||||
browser_cmd_pref.js \
|
||||
browser_cmd_restart.js \
|
||||
browser_cmd_screenshot.html \
|
||||
browser_cmd_settings.js \
|
||||
browser_gcli_canon.js \
|
||||
browser_gcli_cli.js \
|
||||
@ -62,12 +65,14 @@ MOCHITEST_BROWSER_FILES += \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
ifneq ($(OS_ARCH),WINNT)
|
||||
MOCHITEST_BROWSER_FILES += \
|
||||
browser_dbg_cmd_break.html \
|
||||
browser_dbg_cmd.html \
|
||||
browser_cmd_screenshot.html \
|
||||
browser_cmd_pagemod_export.html \
|
||||
browser_cmd_jsb_script.jsi \
|
||||
browser_cmd_calllog.js \
|
||||
browser_cmd_calllog_chrome.js \
|
||||
$(NULL)
|
||||
else
|
||||
$(filter disabled-temporarily--bug-817304, browser_cmd_calllog.js)
|
||||
$(filter disabled-temporarily--bug-819017, browser_cmd_calllog_chrome.js)
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -104,7 +104,7 @@ MOCHITEST_BROWSER_FILES = \
|
||||
browser_webconsole_bug_622303_persistent_filters.js \
|
||||
browser_webconsole_bug_770099_bad_policyuri.js \
|
||||
browser_webconsole_bug_770099_violation.js \
|
||||
browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js \
|
||||
$(filter disabled-temporarily--bug-808264, browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js) \
|
||||
browser_cached_messages.js \
|
||||
browser_bug664688_sandbox_update_after_navigation.js \
|
||||
browser_result_format_as_string.js \
|
||||
|
@ -329,14 +329,32 @@ ElfSection *Elf::getSectionAt(unsigned int offset)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ElfSegment *Elf::getSegmentByType(unsigned int type)
|
||||
ElfSegment *Elf::getSegmentByType(unsigned int type, ElfSegment *last)
|
||||
{
|
||||
for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
|
||||
std::vector<ElfSegment *>::iterator seg;
|
||||
if (last) {
|
||||
seg = std::find(segments.begin(), segments.end(), last);
|
||||
++seg;
|
||||
} else
|
||||
seg = segments.begin();
|
||||
for (; seg != segments.end(); seg++)
|
||||
if ((*seg)->getType() == type)
|
||||
return *seg;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Elf::removeSegment(ElfSegment *segment)
|
||||
{
|
||||
if (!segment)
|
||||
return;
|
||||
std::vector<ElfSegment *>::iterator seg;
|
||||
seg = std::find(segments.begin(), segments.end(), segment);
|
||||
if (seg == segments.end())
|
||||
return;
|
||||
segment->clear();
|
||||
segments.erase(seg);
|
||||
}
|
||||
|
||||
ElfDynamic_Section *Elf::getDynSection()
|
||||
{
|
||||
for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
|
||||
@ -359,20 +377,15 @@ void Elf::normalize()
|
||||
section->getShdr().sh_name = eh_shstrndx->getStrIndex(section->getName());
|
||||
}
|
||||
ehdr->markDirty();
|
||||
// Adjust PT_LOAD segments
|
||||
// Check segments consistency
|
||||
int i = 0;
|
||||
for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++, i++) {
|
||||
if ((*seg)->getType() == PT_LOAD) {
|
||||
std::list<ElfSection *>::iterator it = (*seg)->begin();
|
||||
for (ElfSection *last = *(it++); it != (*seg)->end(); last = *(it++)) {
|
||||
if (((*it)->getType() != SHT_NOBITS) &&
|
||||
((*it)->getAddr() - last->getAddr()) != ((*it)->getOffset() - last->getOffset())) {
|
||||
std::vector<ElfSegment *>::iterator next = seg;
|
||||
segments.insert(++next, (*seg)->splitBefore(*it));
|
||||
seg = segments.begin() + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::list<ElfSection *>::iterator it = (*seg)->begin();
|
||||
for (ElfSection *last = *(it++); it != (*seg)->end(); last = *(it++)) {
|
||||
if (((*it)->getType() != SHT_NOBITS) &&
|
||||
((*it)->getAddr() - last->getAddr()) != ((*it)->getOffset() - last->getOffset())) {
|
||||
throw std::runtime_error("Segments inconsistency");
|
||||
}
|
||||
}
|
||||
}
|
||||
// fixup ehdr before writing
|
||||
@ -481,6 +494,15 @@ unsigned int ElfSection::getOffset()
|
||||
return (shdr.sh_offset = 0);
|
||||
|
||||
unsigned int offset = previous->getOffset();
|
||||
|
||||
ElfSegment *ptload = getSegmentByType(PT_LOAD);
|
||||
ElfSegment *prev_ptload = previous->getSegmentByType(PT_LOAD);
|
||||
|
||||
if (ptload && (ptload == prev_ptload)) {
|
||||
offset += getAddr() - previous->getAddr();
|
||||
return (shdr.sh_offset = offset);
|
||||
}
|
||||
|
||||
if (previous->getType() != SHT_NOBITS)
|
||||
offset += previous->getSize();
|
||||
|
||||
@ -555,6 +577,12 @@ void ElfSegment::addSection(ElfSection *section)
|
||||
section->addToSegment(this);
|
||||
}
|
||||
|
||||
void ElfSegment::removeSection(ElfSection *section)
|
||||
{
|
||||
sections.remove(section);
|
||||
section->removeFromSegment(this);
|
||||
}
|
||||
|
||||
unsigned int ElfSegment::getFileSize()
|
||||
{
|
||||
if (type == PT_GNU_RELRO)
|
||||
@ -605,31 +633,11 @@ unsigned int ElfSegment::getAddr()
|
||||
return sections.empty() ? 0 : sections.front()->getAddr();
|
||||
}
|
||||
|
||||
ElfSegment *ElfSegment::splitBefore(ElfSection *section)
|
||||
void ElfSegment::clear()
|
||||
{
|
||||
std::list<ElfSection *>::iterator i, rm;
|
||||
for (i = sections.begin(); (*i != section) && (i != sections.end()); ++i);
|
||||
if (i == sections.end())
|
||||
return NULL;
|
||||
|
||||
// Probably very wrong.
|
||||
Elf_Phdr phdr;
|
||||
phdr.p_type = type;
|
||||
phdr.p_vaddr = 0;
|
||||
phdr.p_paddr = phdr.p_vaddr + v_p_diff;
|
||||
phdr.p_flags = flags;
|
||||
phdr.p_align = getAlign();
|
||||
phdr.p_filesz = (unsigned int)-1;
|
||||
phdr.p_memsz = (unsigned int)-1;
|
||||
ElfSegment *segment = new ElfSegment(&phdr);
|
||||
|
||||
for (rm = i; i != sections.end(); ++i) {
|
||||
for (std::list<ElfSection *>::iterator i = sections.begin(); i != sections.end(); ++i)
|
||||
(*i)->removeFromSegment(this);
|
||||
segment->addSection(*i);
|
||||
}
|
||||
sections.erase(rm, sections.end());
|
||||
|
||||
return segment;
|
||||
sections.clear();
|
||||
}
|
||||
|
||||
ElfValue *ElfDynamic_Section::getValueForType(unsigned int tag)
|
||||
|
@ -376,6 +376,37 @@ void set_relative_reloc(Elf_Rela *rel, Elf *elf, unsigned int value) {
|
||||
rel->r_addend = value;
|
||||
}
|
||||
|
||||
void maybe_split_segment(Elf *elf, ElfSegment *segment)
|
||||
{
|
||||
std::list<ElfSection *>::iterator it = segment->begin();
|
||||
for (ElfSection *last = *(it++); it != segment->end(); last = *(it++)) {
|
||||
// When two consecutive non-SHT_NOBITS sections are apart by more
|
||||
// than the alignment of the section, the second can be moved closer
|
||||
// to the first, but this requires the segment to be split.
|
||||
if (((*it)->getType() != SHT_NOBITS) && (last->getType() != SHT_NOBITS) &&
|
||||
((*it)->getOffset() - last->getOffset() - last->getSize() > segment->getAlign())) {
|
||||
// Probably very wrong.
|
||||
Elf_Phdr phdr;
|
||||
phdr.p_type = PT_LOAD;
|
||||
phdr.p_vaddr = 0;
|
||||
phdr.p_paddr = phdr.p_vaddr + segment->getVPDiff();
|
||||
phdr.p_flags = segment->getFlags();
|
||||
phdr.p_align = segment->getAlign();
|
||||
phdr.p_filesz = (unsigned int)-1;
|
||||
phdr.p_memsz = (unsigned int)-1;
|
||||
ElfSegment *newSegment = new ElfSegment(&phdr);
|
||||
elf->insertSegmentAfter(segment, newSegment);
|
||||
for (; it != segment->end(); ++it) {
|
||||
newSegment->addSection(*it);
|
||||
}
|
||||
for (it = newSegment->begin(); it != newSegment->end(); it++) {
|
||||
segment->removeSection(*it);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Rel_Type>
|
||||
int do_relocation_section(Elf *elf, unsigned int rel_type, unsigned int rel_type2, bool force)
|
||||
{
|
||||
@ -523,16 +554,23 @@ int do_relocation_section(Elf *elf, unsigned int rel_type, unsigned int rel_type
|
||||
}
|
||||
}
|
||||
|
||||
section->rels.assign(new_rels.begin(), new_rels.end());
|
||||
section->shrink(new_rels.size() * section->getEntSize());
|
||||
|
||||
ElfRelHackCode_Section *relhackcode = new ElfRelHackCode_Section(relhackcode_section, *elf, original_init);
|
||||
relhackcode->insertBefore(section);
|
||||
relhack->insertAfter(relhackcode);
|
||||
|
||||
section->rels.assign(new_rels.begin(), new_rels.end());
|
||||
section->shrink(new_rels.size() * section->getEntSize());
|
||||
if (section->getOffset() + section->getSize() >= old_end) {
|
||||
fprintf(stderr, "No gain. Skipping\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Adjust PT_LOAD segments
|
||||
for (ElfSegment *segment = elf->getSegmentByType(PT_LOAD); segment;
|
||||
segment = elf->getSegmentByType(PT_LOAD, segment)) {
|
||||
maybe_split_segment(elf, segment);
|
||||
}
|
||||
|
||||
// Ensure Elf sections will be at their final location.
|
||||
elf->normalize();
|
||||
ElfLocation *init = new ElfLocation(relhackcode, relhackcode->getEntryPoint());
|
||||
@ -564,49 +602,100 @@ static inline int backup_file(const char *name)
|
||||
void do_file(const char *name, bool backup = false, bool force = false)
|
||||
{
|
||||
std::ifstream file(name, std::ios::in|std::ios::binary);
|
||||
Elf *elf = new Elf(file);
|
||||
unsigned int size = elf->getSize();
|
||||
Elf elf(file);
|
||||
unsigned int size = elf.getSize();
|
||||
fprintf(stderr, "%s: ", name);
|
||||
if (elf->getType() != ET_DYN) {
|
||||
if (elf.getType() != ET_DYN) {
|
||||
fprintf(stderr, "Not a shared object. Skipping\n");
|
||||
delete elf;
|
||||
return;
|
||||
}
|
||||
|
||||
for (ElfSection *section = elf->getSection(1); section != NULL;
|
||||
for (ElfSection *section = elf.getSection(1); section != NULL;
|
||||
section = section->getNext()) {
|
||||
if (section->getName() &&
|
||||
(strncmp(section->getName(), ".elfhack.", 9) == 0)) {
|
||||
fprintf(stderr, "Already elfhacked. Skipping\n");
|
||||
delete elf;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int exit = -1;
|
||||
switch (elf->getMachine()) {
|
||||
switch (elf.getMachine()) {
|
||||
case EM_386:
|
||||
exit = do_relocation_section<Elf_Rel>(elf, R_386_RELATIVE, R_386_32, force);
|
||||
exit = do_relocation_section<Elf_Rel>(&elf, R_386_RELATIVE, R_386_32, force);
|
||||
break;
|
||||
case EM_X86_64:
|
||||
exit = do_relocation_section<Elf_Rela>(elf, R_X86_64_RELATIVE, R_X86_64_64, force);
|
||||
exit = do_relocation_section<Elf_Rela>(&elf, R_X86_64_RELATIVE, R_X86_64_64, force);
|
||||
break;
|
||||
case EM_ARM:
|
||||
exit = do_relocation_section<Elf_Rel>(elf, R_ARM_RELATIVE, R_ARM_ABS32, force);
|
||||
exit = do_relocation_section<Elf_Rel>(&elf, R_ARM_RELATIVE, R_ARM_ABS32, force);
|
||||
break;
|
||||
}
|
||||
if (exit == 0) {
|
||||
if (!force && (elf->getSize() >= size)) {
|
||||
if (!force && (elf.getSize() >= size)) {
|
||||
fprintf(stderr, "No gain. Skipping\n");
|
||||
} else if (backup && backup_file(name) != 0) {
|
||||
fprintf(stderr, "Couln't create backup file\n");
|
||||
} else {
|
||||
std::ofstream ofile(name, std::ios::out|std::ios::binary|std::ios::trunc);
|
||||
elf->write(ofile);
|
||||
fprintf(stderr, "Reduced by %d bytes\n", size - elf->getSize());
|
||||
elf.write(ofile);
|
||||
fprintf(stderr, "Reduced by %d bytes\n", size - elf.getSize());
|
||||
}
|
||||
}
|
||||
delete elf;
|
||||
}
|
||||
|
||||
void undo_file(const char *name, bool backup = false)
|
||||
{
|
||||
std::ifstream file(name, std::ios::in|std::ios::binary);
|
||||
Elf elf(file);
|
||||
unsigned int size = elf.getSize();
|
||||
fprintf(stderr, "%s: ", name);
|
||||
if (elf.getType() != ET_DYN) {
|
||||
fprintf(stderr, "Not a shared object. Skipping\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ElfSection *data = NULL, *text = NULL;
|
||||
for (ElfSection *section = elf.getSection(1); section != NULL;
|
||||
section = section->getNext()) {
|
||||
if (section->getName() &&
|
||||
(strcmp(section->getName(), elfhack_data) == 0))
|
||||
data = section;
|
||||
if (section->getName() &&
|
||||
(strcmp(section->getName(), elfhack_text) == 0))
|
||||
text = section;
|
||||
}
|
||||
|
||||
if (!data || !text) {
|
||||
fprintf(stderr, "Not elfhacked. Skipping\n");
|
||||
return;
|
||||
}
|
||||
if (data != text->getNext()) {
|
||||
fprintf(stderr, elfhack_data " section not following " elfhack_text ". Skipping\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ElfSegment *first = elf.getSegmentByType(PT_LOAD);
|
||||
ElfSegment *second = elf.getSegmentByType(PT_LOAD, first);
|
||||
if (second->getFlags() != first->getFlags()) {
|
||||
fprintf(stderr, "First two PT_LOAD segments don't have the same flags. Skipping\n");
|
||||
return;
|
||||
}
|
||||
// Move sections from the second PT_LOAD to the first, and remove the
|
||||
// second PT_LOAD segment.
|
||||
for (std::list<ElfSection *>::iterator section = second->begin();
|
||||
section != second->end(); ++section)
|
||||
first->addSection(*section);
|
||||
|
||||
elf.removeSegment(second);
|
||||
|
||||
if (backup && backup_file(name) != 0) {
|
||||
fprintf(stderr, "Couln't create backup file\n");
|
||||
} else {
|
||||
std::ofstream ofile(name, std::ios::out|std::ios::binary|std::ios::trunc);
|
||||
elf.write(ofile);
|
||||
fprintf(stderr, "Grown by %d bytes\n", elf.getSize() - size);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@ -614,6 +703,7 @@ int main(int argc, char *argv[])
|
||||
int arg;
|
||||
bool backup = false;
|
||||
bool force = false;
|
||||
bool revert = false;
|
||||
char *lastSlash = rindex(argv[0], '/');
|
||||
if (lastSlash != NULL)
|
||||
rundir = strndup(argv[0], lastSlash - argv[0]);
|
||||
@ -622,6 +712,10 @@ int main(int argc, char *argv[])
|
||||
force = true;
|
||||
else if (strcmp(argv[arg], "-b") == 0)
|
||||
backup = true;
|
||||
else if (strcmp(argv[arg], "-r") == 0)
|
||||
revert = true;
|
||||
else if (revert)
|
||||
undo_file(argv[arg], backup);
|
||||
else
|
||||
do_file(argv[arg], backup, force);
|
||||
}
|
||||
|
@ -270,7 +270,7 @@ public:
|
||||
|
||||
ElfSection *getSectionAt(unsigned int offset);
|
||||
|
||||
ElfSegment *getSegmentByType(unsigned int type);
|
||||
ElfSegment *getSegmentByType(unsigned int type, ElfSegment *last = NULL);
|
||||
|
||||
ElfDynamic_Section *getDynSection();
|
||||
|
||||
@ -282,6 +282,14 @@ public:
|
||||
char getType();
|
||||
char getMachine();
|
||||
unsigned int getSize();
|
||||
|
||||
void insertSegmentAfter(ElfSegment *previous, ElfSegment *segment) {
|
||||
std::vector<ElfSegment *>::iterator prev = std::find(segments.begin(), segments.end(), previous);
|
||||
segments.insert(prev + 1, segment);
|
||||
}
|
||||
|
||||
void removeSegment(ElfSegment *segment);
|
||||
|
||||
private:
|
||||
Elf_Ehdr *ehdr;
|
||||
ElfLocation eh_entry;
|
||||
@ -319,11 +327,8 @@ public:
|
||||
SectionInfo getInfo() { return info; }
|
||||
|
||||
void shrink(unsigned int newsize) {
|
||||
if (newsize < shdr.sh_size) {
|
||||
if (newsize < shdr.sh_size)
|
||||
shdr.sh_size = newsize;
|
||||
if (next)
|
||||
next->markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int getOffset();
|
||||
@ -345,7 +350,7 @@ public:
|
||||
(getType() == SHT_GNU_verdef) ||
|
||||
(getType() == SHT_GNU_verneed) ||
|
||||
(getType() == SHT_GNU_versym) ||
|
||||
isInSegmentType(PT_INTERP)) &&
|
||||
getSegmentByType(PT_INTERP)) &&
|
||||
(getFlags() & SHF_ALLOC);
|
||||
}
|
||||
|
||||
@ -364,6 +369,7 @@ public:
|
||||
next->previous = this;
|
||||
if (dirty)
|
||||
markDirty();
|
||||
insertInSegments(section->segments);
|
||||
}
|
||||
|
||||
void insertBefore(ElfSection *section, bool dirty = true) {
|
||||
@ -381,6 +387,7 @@ public:
|
||||
previous->next = this;
|
||||
if (dirty)
|
||||
markDirty();
|
||||
insertInSegments(section->segments);
|
||||
}
|
||||
|
||||
void markDirty() {
|
||||
@ -415,7 +422,10 @@ private:
|
||||
segments.erase(i, i + 1);
|
||||
}
|
||||
|
||||
bool isInSegmentType(unsigned int type);
|
||||
ElfSegment *getSegmentByType(unsigned int type);
|
||||
|
||||
void insertInSegments(std::vector<ElfSegment *> &segs);
|
||||
|
||||
protected:
|
||||
Elf_Shdr shdr;
|
||||
char *data;
|
||||
@ -444,11 +454,12 @@ public:
|
||||
unsigned int getAddr();
|
||||
|
||||
void addSection(ElfSection *section);
|
||||
void removeSection(ElfSection *section);
|
||||
|
||||
std::list<ElfSection *>::iterator begin() { return sections.begin(); }
|
||||
std::list<ElfSection *>::iterator end() { return sections.end(); }
|
||||
|
||||
ElfSegment *splitBefore(ElfSection *section);
|
||||
void clear();
|
||||
private:
|
||||
unsigned int type;
|
||||
int v_p_diff; // Difference between physical and virtual address
|
||||
@ -643,11 +654,17 @@ inline unsigned int Elf::getSize() {
|
||||
return section->getOffset() + section->getSize();
|
||||
}
|
||||
|
||||
inline bool ElfSection::isInSegmentType(unsigned int type) {
|
||||
inline ElfSegment *ElfSection::getSegmentByType(unsigned int type) {
|
||||
for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
|
||||
if ((*seg)->getType() == type)
|
||||
return true;
|
||||
return false;
|
||||
return *seg;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline void ElfSection::insertInSegments(std::vector<ElfSegment *> &segs) {
|
||||
for (std::vector<ElfSegment *>::iterator it = segs.begin(); it != segs.end(); ++it) {
|
||||
(*it)->addSection(this);
|
||||
}
|
||||
}
|
||||
|
||||
inline ElfLocation::ElfLocation(ElfSection *section, unsigned int off, enum position pos)
|
||||
|
31
content/base/crashtests/816253.html
Normal file
31
content/base/crashtests/816253.html
Normal file
@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
setInterval(
|
||||
function next_step() {
|
||||
var style = document.createElement('style');
|
||||
style.innerHTML = "{ }";
|
||||
document.getElementsByTagName("*")[ 7 ].appendChild(style);
|
||||
window.dump('.');
|
||||
}, 10);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="console"></div>
|
||||
<div id="parentDiv">
|
||||
<div id="left-to-right" dir="auto" class="testElement">
|
||||
<input type="text" value="מקור השם עברית">Test test test
|
||||
</div>
|
||||
</div>
|
||||
<script id="des">
|
||||
var el = document.getElementById("left-to-right");
|
||||
document.defaultView.getComputedStyle(el, null).getPropertyValue('border-right-color');
|
||||
|
||||
document.getElementById("parentDiv").style.display = "none";
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -116,3 +116,4 @@ load 752226-2.html
|
||||
HTTP(..) load xhr_abortinprogress.html
|
||||
load 786854.html
|
||||
load xhr_empty_datauri.html
|
||||
load 816253.html
|
||||
|
@ -732,6 +732,9 @@ void SetAncestorDirectionIfAuto(nsINode* aTextNode, Directionality aDir,
|
||||
// we found the node that set the element's direction after our
|
||||
// text node, so we need to reset the direction
|
||||
resetDirection = true;
|
||||
nsTextNodeDirectionalityMap::RemoveElementFromMap(
|
||||
directionWasSetByTextNode, parent
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -131,7 +131,7 @@ class nsObjectLoadingContent : public nsImageLoadingContent
|
||||
* Used by pluginHost to know if we're loading with a channel, so it
|
||||
* will not open its own.
|
||||
*/
|
||||
bool SrcStreamLoading() { return mSrcStreamLoading; };
|
||||
bool SrcStreamLoading() { return mSrcStreamLoading; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
|
@ -5458,7 +5458,7 @@ nsEventStateManager::WheelPrefs::Init(
|
||||
nsAutoCString prefNameAction(basePrefName);
|
||||
prefNameAction.AppendLiteral("action");
|
||||
int32_t action = Preferences::GetInt(prefNameAction.get(), ACTION_SCROLL);
|
||||
if (action < ACTION_NONE || action > ACTION_LAST) {
|
||||
if (action < int32_t(ACTION_NONE) || action > int32_t(ACTION_LAST)) {
|
||||
NS_WARNING("Unsupported action pref value, replaced with 'Scroll'.");
|
||||
action = ACTION_SCROLL;
|
||||
}
|
||||
@ -5469,7 +5469,7 @@ nsEventStateManager::WheelPrefs::Init(
|
||||
// because this pref is introduced mainly for tilt wheels.
|
||||
prefNameAction.AppendLiteral(".override_x");
|
||||
int32_t actionOverrideX = Preferences::GetInt(prefNameAction.get(), -1);
|
||||
if (actionOverrideX < -1 || actionOverrideX > ACTION_LAST) {
|
||||
if (actionOverrideX < -1 || actionOverrideX > int32_t(ACTION_LAST)) {
|
||||
NS_WARNING("Unsupported action override pref value, didn't override.");
|
||||
actionOverrideX = -1;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ enum MediaEngineState {
|
||||
class MediaEngine
|
||||
{
|
||||
public:
|
||||
virtual ~MediaEngine() {};
|
||||
virtual ~MediaEngine() {}
|
||||
|
||||
/* Populate an array of video sources in the nsTArray. Also include devices
|
||||
* that are currently unavailable. */
|
||||
@ -48,7 +48,7 @@ public:
|
||||
class MediaEngineSource : public nsISupports
|
||||
{
|
||||
public:
|
||||
virtual ~MediaEngineSource() {};
|
||||
virtual ~MediaEngineSource() {}
|
||||
|
||||
/* Populate the human readable name of this device in the nsAString */
|
||||
virtual void GetName(nsAString&) = 0;
|
||||
@ -114,7 +114,7 @@ struct MediaEngineVideoOptions {
|
||||
class MediaEngineVideoSource : public MediaEngineSource
|
||||
{
|
||||
public:
|
||||
virtual ~MediaEngineVideoSource() {};
|
||||
virtual ~MediaEngineVideoSource() {}
|
||||
|
||||
/* Return a MediaEngineVideoOptions struct with appropriate values for all
|
||||
* fields. */
|
||||
@ -127,7 +127,7 @@ public:
|
||||
class MediaEngineAudioSource : public MediaEngineSource
|
||||
{
|
||||
public:
|
||||
virtual ~MediaEngineAudioSource() {};
|
||||
virtual ~MediaEngineAudioSource() {}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ public:
|
||||
if (mList) {
|
||||
mList->mItems[mListIndex] = nullptr;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an unowned copy of an owned length. The caller is responsible for
|
||||
|
@ -71,7 +71,7 @@ public:
|
||||
if (mAList) {
|
||||
( IsAnimValList() ? mAList->mAnimVal : mAList->mBaseVal ) = nullptr;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
|
||||
bool *triedToWrap);
|
||||
|
@ -70,7 +70,7 @@ public:
|
||||
if (mList) {
|
||||
mList->mItems[mListIndex] = nullptr;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an unowned copy. The caller is responsible for the first AddRef().
|
||||
|
@ -81,7 +81,7 @@ public:
|
||||
if (mList) {
|
||||
mList->mItems[mListIndex] = nullptr;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an unowned copy of an owned transform. The caller is responsible for
|
||||
|
@ -5123,8 +5123,8 @@ nsSVGFELightingElement::Filter(nsSVGFilterInstance *instance,
|
||||
S[2] = pointsAt[2] - lightPos[2];
|
||||
NORMALIZE(S);
|
||||
float dot = -DOT(L, S);
|
||||
if (dot < cosConeAngle) dot = 0;
|
||||
float tmp = pow(dot, specularExponent);
|
||||
if (dot < cosConeAngle) tmp = 0;
|
||||
color = NS_RGB(uint8_t(NS_GET_R(lightColor) * tmp),
|
||||
uint8_t(NS_GET_G(lightColor) * tmp),
|
||||
uint8_t(NS_GET_B(lightColor) * tmp));
|
||||
@ -5983,7 +5983,7 @@ nsSVGFEDisplacementMapElement::Filter(nsSVGFilterInstance *instance,
|
||||
uint8_t* targetData = aTarget->mImage->Data();
|
||||
uint32_t stride = aTarget->mImage->Stride();
|
||||
|
||||
static uint8_t dummyData[4] = { 0, 0, 0, 0 };
|
||||
static const uint8_t dummyData[4] = { 0, 0, 0, 0 };
|
||||
|
||||
static const uint16_t channelMap[5] = {
|
||||
0,
|
||||
@ -6010,7 +6010,7 @@ nsSVGFEDisplacementMapElement::Filter(nsSVGFilterInstance *instance,
|
||||
|
||||
bool outOfBounds = sourceX < 0 || sourceX >= width ||
|
||||
sourceY < 0 || sourceY >= height;
|
||||
uint8_t* data;
|
||||
const uint8_t* data;
|
||||
int32_t multiplier;
|
||||
if (outOfBounds) {
|
||||
data = dummyData;
|
||||
|
@ -231,34 +231,6 @@ nsSVGSVGElement::GetHeight(nsIDOMSVGAnimatedLength * *aHeight)
|
||||
return mLengthAttributes[HEIGHT].ToDOMAnimatedLength(aHeight, this);
|
||||
}
|
||||
|
||||
/* attribute DOMString contentScriptType; */
|
||||
NS_IMETHODIMP
|
||||
nsSVGSVGElement::GetContentScriptType(nsAString & aContentScriptType)
|
||||
{
|
||||
NS_NOTYETIMPLEMENTED("nsSVGSVGElement::GetContentScriptType");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsSVGSVGElement::SetContentScriptType(const nsAString & aContentScriptType)
|
||||
{
|
||||
NS_NOTYETIMPLEMENTED("nsSVGSVGElement::SetContentScriptType");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* attribute DOMString contentStyleType; */
|
||||
NS_IMETHODIMP
|
||||
nsSVGSVGElement::GetContentStyleType(nsAString & aContentStyleType)
|
||||
{
|
||||
NS_NOTYETIMPLEMENTED("nsSVGSVGElement::GetContentStyleType");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsSVGSVGElement::SetContentStyleType(const nsAString & aContentStyleType)
|
||||
{
|
||||
NS_NOTYETIMPLEMENTED("nsSVGSVGElement::SetContentStyleType");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* readonly attribute nsIDOMSVGRect viewport; */
|
||||
NS_IMETHODIMP
|
||||
nsSVGSVGElement::GetViewport(nsIDOMSVGRect * *aViewport)
|
||||
|
@ -141,7 +141,7 @@ public:
|
||||
NS_ADDREF(*aStyle);
|
||||
return NS_OK;
|
||||
}
|
||||
NS_FORWARD_NSIFRAMELOADEROWNER(static_cast<nsXULElement*>(mElement.get())->);
|
||||
NS_FORWARD_NSIFRAMELOADEROWNER(static_cast<nsXULElement*>(mElement.get())->)
|
||||
private:
|
||||
nsCOMPtr<nsIDOMXULElement> mElement;
|
||||
};
|
||||
|
@ -47,7 +47,7 @@ this.PermissionsTable = { geolocation: {
|
||||
},
|
||||
camera: {
|
||||
app: DENY_ACTION,
|
||||
privileged: PROMPT_ACTION,
|
||||
privileged: DENY_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
alarms: {
|
||||
@ -235,6 +235,11 @@ this.PermissionsTable = { geolocation: {
|
||||
channels: ["normal", "content", "notification",
|
||||
"alarm", "telephony", "ringer", "publicnotification"]
|
||||
},
|
||||
"open-remote-window": {
|
||||
app: DENY_ACTION,
|
||||
privileged: DENY_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -10,20 +10,16 @@ using namespace mozilla::dom;
|
||||
|
||||
NS_IMPL_ISUPPORTS1(AudioChannelAgent, nsIAudioChannelAgent)
|
||||
|
||||
static nsRefPtr<AudioChannelService> gAudioChannelService;
|
||||
|
||||
AudioChannelAgent::AudioChannelAgent()
|
||||
: mCallback(nullptr)
|
||||
, mAudioChannelType(AUDIO_AGENT_CHANNEL_ERROR)
|
||||
, mIsRegToService(false)
|
||||
, mVisible(true)
|
||||
{
|
||||
gAudioChannelService = AudioChannelService::GetAudioChannelService();
|
||||
}
|
||||
|
||||
AudioChannelAgent::~AudioChannelAgent()
|
||||
{
|
||||
gAudioChannelService = nullptr;
|
||||
}
|
||||
|
||||
/* readonly attribute long audioChannelType; */
|
||||
@ -68,14 +64,15 @@ NS_IMETHODIMP AudioChannelAgent::Init(int32_t channelType, nsIAudioChannelAgentC
|
||||
/* boolean startPlaying (); */
|
||||
NS_IMETHODIMP AudioChannelAgent::StartPlaying(bool *_retval)
|
||||
{
|
||||
AudioChannelService *service = AudioChannelService::GetAudioChannelService();
|
||||
if (mAudioChannelType == AUDIO_AGENT_CHANNEL_ERROR ||
|
||||
gAudioChannelService == nullptr) {
|
||||
service == nullptr) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
gAudioChannelService->RegisterAudioChannelAgent(this,
|
||||
service->RegisterAudioChannelAgent(this,
|
||||
static_cast<AudioChannelType>(mAudioChannelType));
|
||||
*_retval = !gAudioChannelService->GetMuted(static_cast<AudioChannelType>(mAudioChannelType), !mVisible);
|
||||
*_retval = !service->GetMuted(static_cast<AudioChannelType>(mAudioChannelType), !mVisible);
|
||||
mIsRegToService = true;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -88,7 +85,8 @@ NS_IMETHODIMP AudioChannelAgent::StopPlaying(void)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
gAudioChannelService->UnregisterAudioChannelAgent(this);
|
||||
AudioChannelService *service = AudioChannelService::GetAudioChannelService();
|
||||
service->UnregisterAudioChannelAgent(this);
|
||||
mIsRegToService = false;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -100,7 +98,8 @@ NS_IMETHODIMP AudioChannelAgent::SetVisibilityState(bool visible)
|
||||
|
||||
mVisible = visible;
|
||||
if (mIsRegToService && oldVisibility != mVisible && mCallback != nullptr) {
|
||||
mCallback->CanPlayChanged(!gAudioChannelService->GetMuted(static_cast<AudioChannelType>(mAudioChannelType),
|
||||
AudioChannelService *service = AudioChannelService::GetAudioChannelService();
|
||||
mCallback->CanPlayChanged(!service->GetMuted(static_cast<AudioChannelType>(mAudioChannelType),
|
||||
!mVisible));
|
||||
}
|
||||
return NS_OK;
|
||||
@ -109,7 +108,8 @@ NS_IMETHODIMP AudioChannelAgent::SetVisibilityState(bool visible)
|
||||
void AudioChannelAgent::NotifyAudioChannelStateChanged()
|
||||
{
|
||||
if (mCallback != nullptr) {
|
||||
mCallback->CanPlayChanged(!gAudioChannelService->GetMuted(static_cast<AudioChannelType>(mAudioChannelType),
|
||||
AudioChannelService *service = AudioChannelService::GetAudioChannelService();
|
||||
mCallback->CanPlayChanged(!service->GetMuted(static_cast<AudioChannelType>(mAudioChannelType),
|
||||
!mVisible));
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ public:
|
||||
JSObject** aFunctionObject);
|
||||
|
||||
virtual nsIScriptGlobalObject *GetGlobalObject();
|
||||
inline nsIScriptGlobalObject *GetGlobalObjectRef() { return mGlobalObjectRef; };
|
||||
inline nsIScriptGlobalObject *GetGlobalObjectRef() { return mGlobalObjectRef; }
|
||||
|
||||
virtual JSContext* GetNativeContext();
|
||||
virtual JSObject* GetNativeGlobal();
|
||||
|
@ -427,7 +427,7 @@ DOMInterfaces = {
|
||||
|
||||
'WebGLBuffer': {
|
||||
'nativeType': 'mozilla::WebGLBuffer',
|
||||
'headerFile': 'WebGLContext.h'
|
||||
'headerFile': 'WebGLBuffer.h'
|
||||
},
|
||||
|
||||
'WebGLExtensionCompressedTextureATC': {
|
||||
@ -477,17 +477,17 @@ DOMInterfaces = {
|
||||
|
||||
'WebGLFramebuffer': {
|
||||
'nativeType': 'mozilla::WebGLFramebuffer',
|
||||
'headerFile': 'WebGLContext.h'
|
||||
'headerFile': 'WebGLFramebuffer.h'
|
||||
},
|
||||
|
||||
'WebGLProgram': {
|
||||
'nativeType': 'mozilla::WebGLProgram',
|
||||
'headerFile': 'WebGLContext.h'
|
||||
'headerFile': 'WebGLProgram.h'
|
||||
},
|
||||
|
||||
'WebGLRenderbuffer': {
|
||||
'nativeType': 'mozilla::WebGLRenderbuffer',
|
||||
'headerFile': 'WebGLContext.h'
|
||||
'headerFile': 'WebGLRenderbuffer.h'
|
||||
},
|
||||
|
||||
'WebGLRenderingContext': {
|
||||
@ -500,23 +500,23 @@ DOMInterfaces = {
|
||||
|
||||
'WebGLShader': {
|
||||
'nativeType': 'mozilla::WebGLShader',
|
||||
'headerFile': 'WebGLContext.h'
|
||||
'headerFile': 'WebGLShader.h'
|
||||
},
|
||||
|
||||
'WebGLShaderPrecisionFormat': {
|
||||
'nativeType': 'mozilla::WebGLShaderPrecisionFormat',
|
||||
'headerFile': 'WebGLContext.h',
|
||||
'headerFile': 'WebGLShaderPrecisionFormat.h',
|
||||
'wrapperCache': False
|
||||
},
|
||||
|
||||
'WebGLTexture': {
|
||||
'nativeType': 'mozilla::WebGLTexture',
|
||||
'headerFile': 'WebGLContext.h'
|
||||
'headerFile': 'WebGLTexture.h'
|
||||
},
|
||||
|
||||
'WebGLUniformLocation': {
|
||||
'nativeType': 'mozilla::WebGLUniformLocation',
|
||||
'headerFile': 'WebGLContext.h',
|
||||
'headerFile': 'WebGLUniformLocation.h',
|
||||
'wrapperCache': False
|
||||
},
|
||||
|
||||
|
@ -318,6 +318,19 @@ dictionary MozStkPlayTone
|
||||
boolean isVibrate;
|
||||
};
|
||||
|
||||
dictionary MozStkProvideLocalInfo
|
||||
{
|
||||
/**
|
||||
* Indicate which local information is required.
|
||||
* It shall be one of following:
|
||||
* - nsIDOMMozIccManager.STK_LOCAL_INFO_LOCATION_INFO
|
||||
* - nsIDOMMozIccManager.STK_LOCAL_INFO_IMEI
|
||||
* - nsIDOMMozIccManager.STK_LOCAL_INFO_DATE_TIME_ZONE
|
||||
* - nsIDOMMozIccManager.STK_LOCAL_INFO_LANGUAGE
|
||||
*/
|
||||
unsigned short localInfoType;
|
||||
};
|
||||
|
||||
dictionary MozStkLocationEvent
|
||||
{
|
||||
/**
|
||||
@ -403,6 +416,10 @@ dictionary MozStkCommand
|
||||
* options is MozStkDuration.
|
||||
*
|
||||
* When typeOfCommand is
|
||||
* - STK_CMD_PROVIDE_LOCAL_INFO
|
||||
* options is MozStkProvideLocalInfo.
|
||||
*
|
||||
* When typeOfCommand is
|
||||
* - STK_CMD_POLL_OFF
|
||||
* options is null.
|
||||
*
|
||||
@ -458,6 +475,13 @@ dictionary MozStkResponse
|
||||
* false: Rejected by User.
|
||||
*/
|
||||
boolean hasConfirmed;
|
||||
|
||||
/**
|
||||
* The response for STK_CMD_PROVIDE_LOCAL_INFO
|
||||
*
|
||||
* @see MozStkLocalInfo
|
||||
*/
|
||||
jsval localInfo;
|
||||
};
|
||||
|
||||
dictionary MozStkCallEvent
|
||||
@ -493,3 +517,32 @@ dictionary MozStkCallEvent
|
||||
*/
|
||||
DOMString error;
|
||||
};
|
||||
|
||||
dictionary MozStkLocalInfo
|
||||
{
|
||||
/**
|
||||
* IMEI information
|
||||
*/
|
||||
DOMString imei;
|
||||
|
||||
/**
|
||||
* Location Information
|
||||
*
|
||||
* @see MozStkLocationInfo.
|
||||
*/
|
||||
jsval locationInfo;
|
||||
|
||||
/**
|
||||
* Date information
|
||||
*
|
||||
* @see Date
|
||||
*/
|
||||
jsval date;
|
||||
|
||||
/**
|
||||
* Language Information
|
||||
*
|
||||
* @see ISO 639-1, Alpha-2 code
|
||||
*/
|
||||
DOMString language;
|
||||
};
|
||||
|
@ -45,6 +45,7 @@ interface nsIDOMMozIccManager : nsIDOMEventTarget
|
||||
const unsigned short STK_CMD_GET_INPUT = 0x23;
|
||||
const unsigned short STK_CMD_SELECT_ITEM = 0x24;
|
||||
const unsigned short STK_CMD_SET_UP_MENU = 0x25;
|
||||
const unsigned short STK_CMD_PROVIDE_LOCAL_INFO = 0x26;
|
||||
const unsigned short STK_CMD_SET_UP_IDLE_MODE_TEXT = 0x28;
|
||||
|
||||
/**
|
||||
@ -194,6 +195,16 @@ interface nsIDOMMozIccManager : nsIDOMEventTarget
|
||||
const unsigned short STK_TIME_UNIT_SECOND = 0x01;
|
||||
const unsigned short STK_TIME_UNIT_TENTH_SECOND = 0x02;
|
||||
|
||||
/**
|
||||
* Local Information list
|
||||
*
|
||||
* @see TS 102.223, clause 8.6
|
||||
*/
|
||||
const unsigned short STK_LOCAL_INFO_LOCATION_INFO = 0x00;
|
||||
const unsigned short STK_LOCAL_INFO_IMEI = 0x01;
|
||||
const unsigned short STK_LOCAL_INFO_DATE_TIME_ZONE = 0x03;
|
||||
const unsigned short STK_LOCAL_INFO_LANGUAGE = 0x04;
|
||||
|
||||
/**
|
||||
* Send the response back to ICC after an attempt to execute STK Proactive
|
||||
* Command.
|
||||
|
@ -17,9 +17,57 @@ function testDisplayTextGsm7BitEncoding(cmd) {
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
function testLocalInfoLocation(cmd) {
|
||||
log("STK CMD " + JSON.stringify(cmd));
|
||||
is(cmd.typeOfCommand, icc.STK_CMD_PROVIDE_LOCAL_INFO);
|
||||
is(cmd.commandNumber, 0x01);
|
||||
is(cmd.commandQualifier, icc.STK_LOCAL_INFO_LOCATION_INFO);
|
||||
is(cmd.options.localInfoType, icc.STK_LOCAL_INFO_LOCATION_INFO);
|
||||
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
function testLocalInfoImei(cmd) {
|
||||
log("STK CMD " + JSON.stringify(cmd));
|
||||
is(cmd.typeOfCommand, icc.STK_CMD_PROVIDE_LOCAL_INFO);
|
||||
is(cmd.commandNumber, 0x01);
|
||||
is(cmd.commandQualifier, icc.STK_LOCAL_INFO_IMEI);
|
||||
is(cmd.options.localInfoType, icc.STK_LOCAL_INFO_IMEI);
|
||||
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
function testLocalInfoDate(cmd) {
|
||||
log("STK CMD " + JSON.stringify(cmd));
|
||||
is(cmd.typeOfCommand, icc.STK_CMD_PROVIDE_LOCAL_INFO);
|
||||
is(cmd.commandNumber, 0x01);
|
||||
is(cmd.commandQualifier, icc.STK_LOCAL_INFO_DATE_TIME_ZONE);
|
||||
is(cmd.options.localInfoType, icc.STK_LOCAL_INFO_DATE_TIME_ZONE);
|
||||
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
function testLocalInfoLanguage(cmd) {
|
||||
log("STK CMD " + JSON.stringify(cmd));
|
||||
is(cmd.typeOfCommand, icc.STK_CMD_PROVIDE_LOCAL_INFO);
|
||||
is(cmd.commandNumber, 0x01);
|
||||
is(cmd.commandQualifier, icc.STK_LOCAL_INFO_LANGUAGE);
|
||||
is(cmd.options.localInfoType, icc.STK_LOCAL_INFO_LANGUAGE);
|
||||
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
let tests = [
|
||||
{command: "d0288103012180820281020d1d00d3309bfc06c95c301aa8e80259c3ec34b9ac07c9602f58ed159bb940",
|
||||
func: testDisplayTextGsm7BitEncoding},
|
||||
{command: "d009810301260082028182",
|
||||
func: testLocalInfoLocation},
|
||||
{command: "d009810301260182028182",
|
||||
func: testLocalInfoImei},
|
||||
{command: "d009810301260382028182",
|
||||
func: testLocalInfoDate},
|
||||
{command: "d009810301260482028182",
|
||||
func: testLocalInfoLanguage},
|
||||
];
|
||||
|
||||
let pendingEmulatorCmdCount = 0;
|
||||
|
@ -22,7 +22,7 @@ interface nsIDOMSVGTransform;
|
||||
#endif
|
||||
%}
|
||||
|
||||
[scriptable, uuid(BEC06C4F-3EF7-486E-A8F5-F375EE5CB5A8)]
|
||||
[scriptable, uuid(4670a204-4ef1-455f-9595-9847b077c624)]
|
||||
interface nsIDOMSVGSVGElement
|
||||
: nsIDOMSVGElement
|
||||
/*
|
||||
@ -47,10 +47,6 @@ interface nsIDOMSVGSVGElement
|
||||
readonly attribute nsIDOMSVGAnimatedLength y;
|
||||
readonly attribute nsIDOMSVGAnimatedLength width;
|
||||
readonly attribute nsIDOMSVGAnimatedLength height;
|
||||
attribute DOMString contentScriptType;
|
||||
// raises DOMException on setting
|
||||
attribute DOMString contentStyleType;
|
||||
// raises DOMException on setting
|
||||
readonly attribute nsIDOMSVGRect viewport;
|
||||
readonly attribute float pixelUnitToMillimeterX;
|
||||
readonly attribute float pixelUnitToMillimeterY;
|
||||
|
@ -284,6 +284,9 @@ TabChild::OnLocationChange(nsIWebProgress* aWebProgress,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMWindowUtils> utils(do_GetInterface(window));
|
||||
utils->SetIsFirstPaint(true);
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> progressDoc;
|
||||
window->GetDocument(getter_AddRefs(progressDoc));
|
||||
if (!progressDoc) {
|
||||
@ -463,20 +466,27 @@ TabChild::HandlePossibleViewportChange()
|
||||
metrics.mScrollableRect = gfx::Rect(0.0f, 0.0f, pageWidth, pageHeight);
|
||||
metrics.mCompositionBounds = nsIntRect(0, 0, mInnerSize.width, mInnerSize.height);
|
||||
|
||||
gfxSize intrinsicScale =
|
||||
AsyncPanZoomController::CalculateIntrinsicScale(metrics);
|
||||
// FIXME/bug 799585(?): GetViewportInfo() returns a defaultZoom of
|
||||
// 0.0 to mean "did not calculate a zoom". In that case, we default
|
||||
// it to the intrinsic scale.
|
||||
if (viewportInfo.defaultZoom < 0.01f) {
|
||||
viewportInfo.defaultZoom = intrinsicScale.width;
|
||||
// Changing the zoom when we're not doing a first paint will get ignored
|
||||
// by AsyncPanZoomController and causes a blurry flash.
|
||||
bool isFirstPaint;
|
||||
nsresult rv = utils->GetIsFirstPaint(&isFirstPaint);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
if (NS_FAILED(rv) || isFirstPaint) {
|
||||
gfxSize intrinsicScale =
|
||||
AsyncPanZoomController::CalculateIntrinsicScale(metrics);
|
||||
// FIXME/bug 799585(?): GetViewportInfo() returns a defaultZoom of
|
||||
// 0.0 to mean "did not calculate a zoom". In that case, we default
|
||||
// it to the intrinsic scale.
|
||||
if (viewportInfo.defaultZoom < 0.01f) {
|
||||
viewportInfo.defaultZoom = intrinsicScale.width;
|
||||
}
|
||||
MOZ_ASSERT(viewportInfo.minZoom <= viewportInfo.defaultZoom &&
|
||||
viewportInfo.defaultZoom <= viewportInfo.maxZoom);
|
||||
// GetViewportInfo() returns a resolution-dependent scale factor.
|
||||
// Convert that to a resolution-indepedent zoom.
|
||||
metrics.mZoom = gfxSize(viewportInfo.defaultZoom / intrinsicScale.width,
|
||||
viewportInfo.defaultZoom / intrinsicScale.height);
|
||||
}
|
||||
MOZ_ASSERT(viewportInfo.minZoom <= viewportInfo.defaultZoom &&
|
||||
viewportInfo.defaultZoom <= viewportInfo.maxZoom);
|
||||
// GetViewportInfo() returns a resolution-dependent scale factor.
|
||||
// Convert that to a resolution-indepedent zoom.
|
||||
metrics.mZoom = gfxSize(viewportInfo.defaultZoom / intrinsicScale.width,
|
||||
viewportInfo.defaultZoom / intrinsicScale.height);
|
||||
|
||||
metrics.mDisplayPort = AsyncPanZoomController::CalculatePendingDisplayPort(
|
||||
// The page must have been refreshed in some way such as a new document or
|
||||
|
@ -254,13 +254,13 @@ public:
|
||||
mSource = aSource;
|
||||
mType.Assign(NS_LITERAL_STRING("video"));
|
||||
mSource->GetName(mName);
|
||||
};
|
||||
}
|
||||
MediaDevice(MediaEngineAudioSource* aSource) {
|
||||
mSource = aSource;
|
||||
mType.Assign(NS_LITERAL_STRING("audio"));
|
||||
mSource->GetName(mName);
|
||||
};
|
||||
virtual ~MediaDevice() {};
|
||||
}
|
||||
virtual ~MediaDevice() {}
|
||||
|
||||
MediaEngineSource* GetSource();
|
||||
private:
|
||||
@ -317,7 +317,7 @@ private:
|
||||
WindowTable *GetActiveWindows() {
|
||||
NS_ASSERTION(NS_IsMainThread(), "Only access windowlist on main thread");
|
||||
return &mActiveWindows;
|
||||
};
|
||||
}
|
||||
|
||||
// Make private because we want only one instance of this class
|
||||
MediaManager()
|
||||
@ -326,11 +326,11 @@ private:
|
||||
, mBackend(nullptr) {
|
||||
mActiveWindows.Init();
|
||||
mActiveCallbacks.Init();
|
||||
};
|
||||
}
|
||||
|
||||
~MediaManager() {
|
||||
delete mBackend;
|
||||
};
|
||||
}
|
||||
|
||||
// ONLY access from MainThread so we don't need to lock
|
||||
WindowTable mActiveWindows;
|
||||
|
70
dom/media/tests/crashtests/812785.html
Normal file
70
dom/media/tests/crashtests/812785.html
Normal file
@ -0,0 +1,70 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=812785
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Bug 812785 - WebRTC use-after-free crash</title>
|
||||
<script type="application/javascript">
|
||||
var pc1, pc2, pc1_offer, pc2_answer, localAudio, remoteAudio;
|
||||
|
||||
function onFailure(code) {
|
||||
stop();
|
||||
}
|
||||
|
||||
function stop() {
|
||||
pc1.close(); pc1 = null;
|
||||
pc2.close(); pc2 = null;
|
||||
|
||||
var index = localStorage.index || 0;
|
||||
if (index < 5) {
|
||||
localStorage.index = index + 1;
|
||||
window.location.reload();
|
||||
}
|
||||
else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
function start() {
|
||||
localAudio = document.getElementById("local");
|
||||
remoteAudio = document.getElementById("remote");
|
||||
|
||||
var stream = localAudio.mozCaptureStreamUntilEnded();
|
||||
|
||||
pc1 = new mozRTCPeerConnection();
|
||||
pc2 = new mozRTCPeerConnection();
|
||||
|
||||
pc1.addStream(stream);
|
||||
pc1.createOffer(function (offer) {
|
||||
pc1_offer = offer;
|
||||
pc1.setLocalDescription(pc1_offer, function () {
|
||||
pc2.setRemoteDescription(pc1_offer, function () {
|
||||
pc2.createAnswer(function (answer) {
|
||||
pc2_answer = answer;
|
||||
pc2.setLocalDescription(pc2_answer, function () {
|
||||
pc1.setRemoteDescription(pc2_answer, function step6() {
|
||||
stop();
|
||||
}, onFailure);
|
||||
}, onFailure);
|
||||
}, onFailure);
|
||||
}, onFailure);
|
||||
}, onFailure);
|
||||
}, onFailure);
|
||||
}
|
||||
|
||||
function finish() {
|
||||
delete localStorage["index"];
|
||||
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="start()">
|
||||
<audio id="local" controls autoplay><source type="audio/wav" src="" /></audio>
|
||||
<audio id="remote" controls></audio>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -6,3 +6,4 @@ load 791278.html
|
||||
load 791330.html
|
||||
load 801227.html
|
||||
load 802982.html
|
||||
load 812785.html
|
||||
|
@ -186,12 +186,20 @@ enum eNPPStreamTypeInternal {
|
||||
|
||||
static NS_DEFINE_IID(kMemoryCID, NS_MEMORY_CID);
|
||||
|
||||
PRIntervalTime NS_NotifyBeginPluginCall()
|
||||
{
|
||||
nsNPAPIPluginInstance::BeginPluginCall();
|
||||
return PR_IntervalNow();
|
||||
}
|
||||
|
||||
// This function sends a notification using the observer service to any object
|
||||
// registered to listen to the "experimental-notify-plugin-call" subject.
|
||||
// Each "experimental-notify-plugin-call" notification carries with it the run
|
||||
// time value in milliseconds that the call took to execute.
|
||||
void NS_NotifyPluginCall(PRIntervalTime startTime)
|
||||
{
|
||||
nsNPAPIPluginInstance::EndPluginCall();
|
||||
|
||||
PRIntervalTime endTime = PR_IntervalNow() - startTime;
|
||||
nsCOMPtr<nsIObserverService> notifyUIService =
|
||||
mozilla::services::GetObserverService();
|
||||
|
@ -200,6 +200,8 @@ nsNPAPIPluginInstance::~nsNPAPIPluginInstance()
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t nsNPAPIPluginInstance::gInPluginCalls = 0;
|
||||
|
||||
void
|
||||
nsNPAPIPluginInstance::Destroy()
|
||||
{
|
||||
|
@ -270,6 +270,14 @@ public:
|
||||
// Returns the contents scale factor of the screen the plugin is drawn on.
|
||||
double GetContentsScaleFactor();
|
||||
|
||||
static bool InPluginCall() { return gInPluginCalls > 0; }
|
||||
static void BeginPluginCall() { ++gInPluginCalls; }
|
||||
static void EndPluginCall()
|
||||
{
|
||||
NS_ASSERTION(InPluginCall(), "Must be in plugin call");
|
||||
--gInPluginCalls;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
nsresult GetTagType(nsPluginTagType *result);
|
||||
@ -364,6 +372,8 @@ private:
|
||||
|
||||
// is this instance Java and affected by bug 750480?
|
||||
bool mHaveJavaC2PJSObjectQuirk;
|
||||
|
||||
static uint32_t gInPluginCalls;
|
||||
};
|
||||
|
||||
#endif // nsNPAPIPluginInstance_h_
|
||||
|
@ -14,6 +14,7 @@
|
||||
#define CALL_SAFETY_ON
|
||||
#endif
|
||||
|
||||
PRIntervalTime NS_NotifyBeginPluginCall();
|
||||
void NS_NotifyPluginCall(PRIntervalTime);
|
||||
|
||||
#ifdef CALL_SAFETY_ON
|
||||
@ -31,7 +32,7 @@ PR_END_MACRO
|
||||
|
||||
#define NS_TRY_SAFE_CALL_RETURN(ret, fun, pluginInst) \
|
||||
PR_BEGIN_MACRO \
|
||||
PRIntervalTime startTime = PR_IntervalNow(); \
|
||||
PRIntervalTime startTime = NS_NotifyBeginPluginCall(); \
|
||||
if(gSkipPluginSafeCalls) \
|
||||
ret = fun; \
|
||||
else \
|
||||
@ -40,7 +41,7 @@ PR_BEGIN_MACRO \
|
||||
{ \
|
||||
ret = fun; \
|
||||
} \
|
||||
MOZ_SEH_EXCEPT(true) \
|
||||
MOZ_SEH_EXCEPT(true) \
|
||||
{ \
|
||||
nsresult res; \
|
||||
nsCOMPtr<nsIPluginHost> host(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID, &res));\
|
||||
@ -54,7 +55,7 @@ PR_END_MACRO
|
||||
|
||||
#define NS_TRY_SAFE_CALL_VOID(fun, pluginInst) \
|
||||
PR_BEGIN_MACRO \
|
||||
PRIntervalTime startTime = PR_IntervalNow(); \
|
||||
PRIntervalTime startTime = NS_NotifyBeginPluginCall(); \
|
||||
if(gSkipPluginSafeCalls) \
|
||||
fun; \
|
||||
else \
|
||||
@ -63,7 +64,7 @@ PR_BEGIN_MACRO \
|
||||
{ \
|
||||
fun; \
|
||||
} \
|
||||
MOZ_SEH_EXCEPT(true) \
|
||||
MOZ_SEH_EXCEPT(true) \
|
||||
{ \
|
||||
nsresult res; \
|
||||
nsCOMPtr<nsIPluginHost> host(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID, &res));\
|
||||
@ -78,16 +79,16 @@ PR_END_MACRO
|
||||
|
||||
#define NS_TRY_SAFE_CALL_RETURN(ret, fun, pluginInst) \
|
||||
PR_BEGIN_MACRO \
|
||||
PRIntervalTime startTime = PR_IntervalNow(); \
|
||||
PRIntervalTime startTime = NS_NotifyBeginPluginCall(); \
|
||||
ret = fun; \
|
||||
NS_NotifyPluginCall(startTime); \
|
||||
NS_NotifyPluginCall(startTime); \
|
||||
PR_END_MACRO
|
||||
|
||||
#define NS_TRY_SAFE_CALL_VOID(fun, pluginInst) \
|
||||
PR_BEGIN_MACRO \
|
||||
PRIntervalTime startTime = PR_IntervalNow(); \
|
||||
fun; \
|
||||
NS_NotifyPluginCall(startTime); \
|
||||
#define NS_TRY_SAFE_CALL_VOID(fun, pluginInst) \
|
||||
PR_BEGIN_MACRO \
|
||||
PRIntervalTime startTime = NS_NotifyBeginPluginCall(); \
|
||||
fun; \
|
||||
NS_NotifyPluginCall(startTime); \
|
||||
PR_END_MACRO
|
||||
|
||||
#endif // CALL_SAFETY_ON
|
||||
|
@ -24,3 +24,4 @@ qemu = true
|
||||
[test_number_of_messages.js]
|
||||
[test_mark_msg_read.js]
|
||||
[test_mark_msg_read_error.js]
|
||||
[test_bug814761.js]
|
||||
|
70
dom/sms/tests/marionette/test_bug814761.js
Normal file
70
dom/sms/tests/marionette/test_bug814761.js
Normal file
@ -0,0 +1,70 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 20000;
|
||||
|
||||
SpecialPowers.setBoolPref("dom.sms.enabled", true);
|
||||
SpecialPowers.addPermission("sms", true, document);
|
||||
|
||||
let sms = window.navigator.mozSms;
|
||||
|
||||
// Note: 378 chars and below is fine, but 379 and above will cause the issue.
|
||||
// Sending first message works, but second one we get emulator callback but
|
||||
// the actual SMS is never received, so script will timeout waiting for the
|
||||
// sms.onreceived event. Also note that a single larger message (i.e. 1600
|
||||
// characters) works; so it is not a compounded send limit.
|
||||
let fromNumber = "5551110000";
|
||||
let msgLength = 379;
|
||||
let msgText = new Array(msgLength + 1).join('a');
|
||||
|
||||
let pendingEmulatorCmdCount = 0;
|
||||
function sendSmsToEmulator(from, text) {
|
||||
++pendingEmulatorCmdCount;
|
||||
|
||||
let cmd = "sms send " + from + " " + text;
|
||||
runEmulatorCmd(cmd, function (result) {
|
||||
--pendingEmulatorCmdCount;
|
||||
|
||||
is(result[0], "OK", "Emulator response");
|
||||
});
|
||||
}
|
||||
|
||||
function firstIncomingSms() {
|
||||
simulateIncomingSms(secondIncomingSms);
|
||||
}
|
||||
|
||||
function secondIncomingSms() {
|
||||
simulateIncomingSms(cleanUp);
|
||||
}
|
||||
|
||||
function simulateIncomingSms(nextFunction) {
|
||||
log("Simulating incoming multipart SMS (" + msgText.length
|
||||
+ " chars total).");
|
||||
|
||||
sms.onreceived = function onreceived(event) {
|
||||
log("Received 'onreceived' smsmanager event.");
|
||||
sms.onreceived = null;
|
||||
|
||||
let incomingSms = event.message;
|
||||
ok(incomingSms, "incoming sms");
|
||||
is(incomingSms.body, msgText, "msg body");
|
||||
|
||||
window.setTimeout(nextFunction, 0);
|
||||
};
|
||||
|
||||
sendSmsToEmulator(fromNumber, msgText);
|
||||
}
|
||||
|
||||
function cleanUp() {
|
||||
if (pendingEmulatorCmdCount) {
|
||||
window.setTimeout(cleanUp, 100);
|
||||
return;
|
||||
}
|
||||
|
||||
SpecialPowers.removePermission("sms", document);
|
||||
SpecialPowers.clearUserPref("dom.sms.enabled");
|
||||
finish();
|
||||
}
|
||||
|
||||
// Start the test
|
||||
firstIncomingSms();
|
@ -555,7 +555,9 @@ this.COMPREHENSIONTLV_TAG_ITEM_ID = 0x10;
|
||||
this.COMPREHENSIONTLV_TAG_RESPONSE_LENGTH = 0x11;
|
||||
this.COMPREHENSIONTLV_TAG_FILE_LIST = 0x12;
|
||||
this.COMPREHENSIONTLV_TAG_LOCATION_INFO = 0x13;
|
||||
this.COMPREHENSIONTLV_TAG_IMEI = 0x14;
|
||||
this.COMPREHENSIONTLV_TAG_HELP_REQUEST = 0x15;
|
||||
this.COMPREHENSIONTLV_TAG_NMR = 0x16;
|
||||
this.COMPREHENSIONTLV_TAG_DEFAULT_TEXT = 0x17;
|
||||
this.COMPREHENSIONTLV_TAG_CAUSE = 0x1a;
|
||||
this.COMPREHENSIONTLV_TAG_LOCATION_STATUS = 0x1b;
|
||||
@ -563,8 +565,17 @@ this.COMPREHENSIONTLV_TAG_TRANSACTION_ID = 0x1c;
|
||||
this.COMPREHENSIONTLV_TAG_EVENT_LIST = 0x19;
|
||||
this.COMPREHENSIONTLV_TAG_ICON_ID = 0x1e;
|
||||
this.COMPREHENSIONTLV_TAG_ICON_ID_LIST = 0x1f;
|
||||
this.COMPREHENSIONTLV_TAG_DATE_TIME_ZONE = 0x26;
|
||||
this.COMPREHENSIONTLV_TAG_IMMEDIATE_RESPONSE = 0x2b;
|
||||
this.COMPREHENSIONTLV_TAG_LANGUAGE = 0x2d;
|
||||
this.COMPREHENSIONTLV_TAG_URL = 0x31;
|
||||
this.COMPREHENSIONTLV_TAG_ACCESS_TECH = 0x3f;
|
||||
this.COMPREHENSIONTLV_TAG_SERVICE_RECORD = 0x41;
|
||||
this.COMPREHENSIONTLV_TAG_IMEISV = 0x62;
|
||||
this.COMPREHENSIONTLV_TAG_BATTERY_STATE = 0x63;
|
||||
this.COMPREHENSIONTLV_TAG_NETWORK_SEARCH_MODE = 0x65;
|
||||
this.COMPREHENSIONTLV_TAG_MEID = 0x6d;
|
||||
this.COMPREHENSIONTLV_TAG_BROADCAST_NETWORK_INFO = 0x7a;
|
||||
|
||||
// Tags for Service Provider Display Information TLV
|
||||
this.SPDI_TAG_SPDI = 0xa3;
|
||||
@ -596,6 +607,7 @@ this.STK_CMD_GET_INKEY = 0x22;
|
||||
this.STK_CMD_GET_INPUT = 0x23;
|
||||
this.STK_CMD_SELECT_ITEM = 0x24;
|
||||
this.STK_CMD_SET_UP_MENU = 0x25;
|
||||
this.STK_CMD_PROVIDE_LOCAL_INFO = 0x26;
|
||||
this.STK_CMD_SET_UP_IDLE_MODE_TEXT = 0x28;
|
||||
|
||||
// STK Result code.
|
||||
@ -781,6 +793,23 @@ this.STK_TIME_UNIT_MINUTE = 0x00;
|
||||
this.STK_TIME_UNIT_SECOND = 0x01;
|
||||
this.STK_TIME_UNIT_TENTH_SECOND = 0x02;
|
||||
|
||||
// Local Information type.
|
||||
this.STK_LOCAL_INFO_NNA = 0x00;
|
||||
this.STK_LOCAL_INFO_IMEI = 0x01;
|
||||
this.STK_LOCAL_INFO_NMR_FOR_NNA = 0x02;
|
||||
this.STK_LOCAL_INFO_DATE_TIME_ZONE = 0x03;
|
||||
this.STK_LOCAL_INFO_LANGUAGE = 0x04;
|
||||
this.STK_LOCAL_INFO_ACCESS_TECH = 0x06;
|
||||
this.STK_LOCAL_INFO_ESN = 0x07;
|
||||
this.STK_LOCAL_INFO_IMEISV = 0x08;
|
||||
this.STK_LOCAL_INFO_SEARCH_MODE = 0x09;
|
||||
this.STK_LOCAL_INFO_CHARGE_STATE = 0x0A;
|
||||
this.STK_LOCAL_INFO_MEID = 0x0B;
|
||||
this.STK_LOCAL_INFO_BROADCAST_NETWORK_INFO = 0x0D;
|
||||
this.STK_LOCAL_INFO_MULTIPLE_ACCESS_TECH = 0x0E;
|
||||
this.STK_LOCAL_INFO_INFO_FOR_MULTIPLE_ACCESS_TECH = 0x0F;
|
||||
this.STK_LOCAL_INFO_NMR_FOR_MULTIPLE_ACCESS_TECH = 0x10;
|
||||
|
||||
/**
|
||||
* Supported Terminal Facilities.
|
||||
*
|
||||
@ -820,7 +849,7 @@ this.STK_TERMINAL_SUPPORT_PROACTIVE_SEND_SS = 1;
|
||||
this.STK_TERMINAL_SUPPORT_PROACTIVE_SEND_USSD = 1;
|
||||
this.STK_TERMINAL_SUPPORT_PROACTIVE_SET_UP_CALL = 1;
|
||||
this.STK_TERMINAL_SUPPORT_PROACTIVE_SET_UP_MENU = 1;
|
||||
this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO = 0;
|
||||
this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO = 1;
|
||||
this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_NMR = 0;
|
||||
|
||||
this.STK_TERMINAL_SUPPORT_PROACTIVE_SET_UP_EVENT_LIST = 1;
|
||||
@ -832,6 +861,24 @@ this.STK_TERMINAL_SUPPORT_EVENT_USER_ACTIVITY = 0;
|
||||
this.STK_TERMINAL_SUPPORT_EVENT_IDLE_SCREEN_AVAILABLE = 0;
|
||||
this.STK_TERMINAL_SUPPORT_EVENT_CARD_READER_STATUS = 0;
|
||||
|
||||
this.STK_TERMINAL_SUPPORT_PROACTIVE_TIMER_START_STOP = 0;
|
||||
this.STK_TERMINAL_SUPPORT_PROACTIVE_TIMER_GET_CURRENT = 0;
|
||||
this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_DATE = 1;
|
||||
this.STK_TERMINAL_SUPPORT_GET_INKEY = 1;
|
||||
this.STK_TERMINAL_SUPPORT_SET_UP_IDLE_MODE_TEXT = 1;
|
||||
this.STK_TERMINAL_SUPPORT_RUN_AT_COMMAND = 0;
|
||||
this.STK_TERMINAL_SUPPORT_SET_UP_CALL = 1;
|
||||
this.STK_TERMINAL_SUPPORT_CALL_CONTROL_BY_NNA = 0;
|
||||
|
||||
this.STK_TERMINAL_SUPPORT_DISPLAY_TEXT = 1;
|
||||
this.STK_TERMINAL_SUPPORT_SEND_DTMF_COMMAND = 1;
|
||||
this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_NMR = 0;
|
||||
this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_LANGUAGE = 1;
|
||||
this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_TIME_ADVANCE = 0;
|
||||
this.STK_TERMINAL_SUPPORT_PROACTIVE_LANGUAGE_NOTIFICATION = 0;
|
||||
this.STK_TERMINAL_SUPPORT_PROACTIVE_LAUNCH_BROWSER = 1;
|
||||
this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_ACCESS_TECH = 0;
|
||||
|
||||
this.STK_TERMINAL_PROFILE_DOWNLOAD =
|
||||
(STK_TERMINAL_SUPPORT_PROFILE_DOWNLOAD << 0) |
|
||||
(STK_TERMINAL_SUPPORT_SMS_PP_DOWNLOAD << 1) |
|
||||
@ -882,6 +929,26 @@ this.STK_TERMINAL_PROFILE_EVENT =
|
||||
(STK_TERMINAL_SUPPORT_EVENT_IDLE_SCREEN_AVAILABLE << 6) |
|
||||
(STK_TERMINAL_SUPPORT_EVENT_CARD_READER_STATUS << 7);
|
||||
|
||||
this.STK_TERMINAL_PROFILE_PROACTIVE_3 =
|
||||
(STK_TERMINAL_SUPPORT_PROACTIVE_TIMER_START_STOP << 0) |
|
||||
(STK_TERMINAL_SUPPORT_PROACTIVE_TIMER_GET_CURRENT << 1) |
|
||||
(STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_DATE << 2) |
|
||||
(STK_TERMINAL_SUPPORT_GET_INKEY << 3) |
|
||||
(STK_TERMINAL_SUPPORT_SET_UP_IDLE_MODE_TEXT << 4) |
|
||||
(STK_TERMINAL_SUPPORT_RUN_AT_COMMAND << 5) |
|
||||
(STK_TERMINAL_SUPPORT_SET_UP_CALL << 6) |
|
||||
(STK_TERMINAL_SUPPORT_CALL_CONTROL_BY_NNA << 7);
|
||||
|
||||
this.STK_TERMINAL_PROFILE_PROACTIVE_4 =
|
||||
(STK_TERMINAL_SUPPORT_DISPLAY_TEXT << 0) |
|
||||
(STK_TERMINAL_SUPPORT_SEND_DTMF_COMMAND << 1) |
|
||||
(STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_NMR << 2) |
|
||||
(STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_LANGUAGE << 3) |
|
||||
(STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_TIME_ADVANCE << 4) |
|
||||
(STK_TERMINAL_SUPPORT_PROACTIVE_LANGUAGE_NOTIFICATION << 5) |
|
||||
(STK_TERMINAL_SUPPORT_PROACTIVE_LAUNCH_BROWSER << 6) |
|
||||
(STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_ACCESS_TECH << 7);
|
||||
|
||||
this.STK_SUPPORTED_TERMINAL_PROFILE = [
|
||||
STK_TERMINAL_PROFILE_DOWNLOAD,
|
||||
STK_TERMINAL_PROFILE_OTHER,
|
||||
@ -890,8 +957,8 @@ this.STK_SUPPORTED_TERMINAL_PROFILE = [
|
||||
STK_TERMINAL_PROFILE_EVENT,
|
||||
0x00, // Event extension
|
||||
0x00, // Multiple card proactive commands
|
||||
0x00, // Proactive Commands
|
||||
0x00, // Proactive Commands
|
||||
STK_TERMINAL_PROFILE_PROACTIVE_3,
|
||||
STK_TERMINAL_PROFILE_PROACTIVE_4,
|
||||
0x00, // Softkey support
|
||||
0x00, // Softkey information
|
||||
0x00, // BIP proactive commands
|
||||
|
@ -60,6 +60,9 @@ const TLV_EVENT_LIST_SIZE = 3;
|
||||
const TLV_LOCATION_STATUS_SIZE = 3;
|
||||
const TLV_LOCATION_INFO_GSM_SIZE = 9;
|
||||
const TLV_LOCATION_INFO_UMTS_SIZE = 11;
|
||||
const TLV_IMEI_SIZE = 10;
|
||||
const TLV_DATE_TIME_ZONE_SIZE = 9;
|
||||
const TLV_LANGUAGE_SIZE = 4;
|
||||
|
||||
const DEFAULT_EMERGENCY_NUMBERS = ["112", "911"];
|
||||
|
||||
@ -475,8 +478,9 @@ let Buf = {
|
||||
// we process any backlog in parcels immediately, before writing
|
||||
// new data to the buffer. So the only edge case we need to handle
|
||||
// is when the incoming data is larger than the buffer size.
|
||||
if (incoming.length > this.INCOMING_BUFFER_LENGTH) {
|
||||
this.growIncomingBuffer(incoming.length);
|
||||
let minMustAvailableSize = incoming.length + this.readIncoming;
|
||||
if (minMustAvailableSize > this.INCOMING_BUFFER_LENGTH) {
|
||||
this.growIncomingBuffer(minMustAvailableSize);
|
||||
}
|
||||
|
||||
// We can let the typed arrays do the copying if the incoming data won't
|
||||
@ -585,6 +589,13 @@ let Buf = {
|
||||
let error = this.readUint32();
|
||||
|
||||
options = this.tokenRequestMap[token];
|
||||
if (!options) {
|
||||
if (DEBUG) {
|
||||
debug("Suspicious uninvited request found: " + token + ". Ignored!");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
delete this.tokenRequestMap[token];
|
||||
request_type = options.rilRequestType;
|
||||
|
||||
@ -3118,11 +3129,13 @@ let RIL = {
|
||||
* Send STK terminal response.
|
||||
*
|
||||
* @param command
|
||||
* @param deviceIdentities
|
||||
* @param resultCode
|
||||
* @param [optional] itemIdentifier
|
||||
* @param [optional] input
|
||||
* @param [optional] isYesNo
|
||||
* @param [optional] hasConfirmed
|
||||
* @param [optional] localInfo
|
||||
*/
|
||||
sendStkTerminalResponse: function sendStkTerminalResponse(response) {
|
||||
if (response.hasConfirmed !== undefined) {
|
||||
@ -3154,6 +3167,18 @@ let RIL = {
|
||||
TLV_RESULT_SIZE +
|
||||
(response.itemIdentifier ? TLV_ITEM_ID_SIZE : 0) +
|
||||
(textLen ? textLen + 3 : 0)) * 2;
|
||||
if (response.localInfo) {
|
||||
let localInfo = response.localInfo;
|
||||
size = size +
|
||||
(((localInfo.locationInfo ?
|
||||
(localInfo.locationInfo.gsmCellId > 0xffff ?
|
||||
TLV_LOCATION_INFO_UMTS_SIZE :
|
||||
TLV_LOCATION_INFO_GSM_SIZE) :
|
||||
0) +
|
||||
(localInfo.imei ? TLV_IMEI_SIZE : 0) +
|
||||
(localInfo.date ? TLV_DATE_TIME_ZONE_SIZE : 0) +
|
||||
(localInfo.language ? TLV_LANGUAGE_SIZE : 0)) * 2);
|
||||
}
|
||||
Buf.writeUint32(size);
|
||||
|
||||
// Command Details
|
||||
@ -3238,6 +3263,40 @@ let RIL = {
|
||||
}
|
||||
}
|
||||
|
||||
// Local Information
|
||||
if (response.localInfo) {
|
||||
let localInfo = response.localInfo;
|
||||
|
||||
// Location Infomation
|
||||
if (localInfo.locationInfo) {
|
||||
ComprehensionTlvHelper.writeLocationInfoTlv(localInfo.locationInfo);
|
||||
}
|
||||
|
||||
// IMEI
|
||||
if (localInfo.imei) {
|
||||
let imei = localInfo.imei;
|
||||
if(imei.length == 15) {
|
||||
imei = imei + "0";
|
||||
}
|
||||
|
||||
GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_IMEI);
|
||||
GsmPDUHelper.writeHexOctet(8);
|
||||
for (let i = 0; i < imei.length / 2; i++) {
|
||||
GsmPDUHelper.writeHexOctet(parseInt(imei.substr(i * 2, 2), 16));
|
||||
}
|
||||
}
|
||||
|
||||
// Date and Time Zone
|
||||
if (localInfo.date) {
|
||||
ComprehensionTlvHelper.writeDateTimeZoneTlv(localInfo.date);
|
||||
}
|
||||
|
||||
// Language
|
||||
if (localInfo.language) {
|
||||
ComprehensionTlvHelper.writeLanguageTlv(localInfo.language);
|
||||
}
|
||||
}
|
||||
|
||||
Buf.writeUint32(0);
|
||||
Buf.sendParcel();
|
||||
},
|
||||
@ -6120,6 +6179,20 @@ let GsmPDUHelper = {
|
||||
((octet & 0x0f) <= 0x09) * (octet & 0x0f) * 10;
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert a BCD number to an octet (number)
|
||||
*
|
||||
* Only take two digits with absolute value.
|
||||
*
|
||||
* @param bcd
|
||||
*
|
||||
* @return the corresponding octet.
|
||||
*/
|
||||
BCDToOctet: function BCDToOctet(bcd) {
|
||||
bcd = Math.abs(bcd);
|
||||
return ((bcd % 10) << 4) + (Math.floor(bcd / 10) % 10);
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert a semi-octet (number) to a GSM BCD char.
|
||||
*/
|
||||
@ -6204,6 +6277,24 @@ let GsmPDUHelper = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Write numerical data as swapped nibble BCD.
|
||||
* If the number of digit of data is even, add '0' at the beginning.
|
||||
*
|
||||
* @param data
|
||||
* Data to write (as a string or a number)
|
||||
*/
|
||||
writeSwappedNibbleBCDNum: function writeSwappedNibbleBCDNum(data) {
|
||||
data = data.toString();
|
||||
if (data.length % 2) {
|
||||
data = "0" + data;
|
||||
}
|
||||
for (let i = 0; i < data.length; i += 2) {
|
||||
Buf.writeUint16(data.charCodeAt(i + 1));
|
||||
Buf.writeUint16(data.charCodeAt(i));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Read user data, convert to septets, look up relevant characters in a
|
||||
* 7-bit alphabet, and construct string.
|
||||
@ -7028,6 +7119,43 @@ let GsmPDUHelper = {
|
||||
return timestamp;
|
||||
},
|
||||
|
||||
/**
|
||||
* Write GSM TP-Service-Centre-Time-Stamp(TP-SCTS).
|
||||
*
|
||||
* @see 3GPP TS 23.040 9.2.3.11
|
||||
*/
|
||||
writeTimestamp: function writeTimestamp(date) {
|
||||
this.writeSwappedNibbleBCDNum(date.getFullYear() - PDU_TIMESTAMP_YEAR_OFFSET);
|
||||
|
||||
// The value returned by getMonth() is an integer between 0 and 11.
|
||||
// 0 is corresponds to January, 1 to February, and so on.
|
||||
this.writeSwappedNibbleBCDNum(date.getMonth() + 1);
|
||||
this.writeSwappedNibbleBCDNum(date.getDate());
|
||||
this.writeSwappedNibbleBCDNum(date.getHours());
|
||||
this.writeSwappedNibbleBCDNum(date.getMinutes());
|
||||
this.writeSwappedNibbleBCDNum(date.getSeconds());
|
||||
|
||||
// the value returned by getTimezoneOffset() is the difference,
|
||||
// in minutes, between UTC and local time.
|
||||
// For example, if your time zone is UTC+10 (Australian Eastern Standard Time),
|
||||
// -600 will be returned.
|
||||
// In TS 23.040 9.2.3.11, the Time Zone field of TP-SCTS indicates
|
||||
// the different between the local time and GMT.
|
||||
// And expressed in quarters of an hours. (so need to divid by 15)
|
||||
let zone = date.getTimezoneOffset() / 15;
|
||||
let octet = this.BCDToOctet(zone);
|
||||
|
||||
// the bit3 of the Time Zone field represents the algebraic sign.
|
||||
// (0: positive, 1: negative).
|
||||
// For example, if the time zone is -0800 GMT,
|
||||
// 480 will be returned by getTimezoneOffset().
|
||||
// In this case, need to mark sign bit as 1. => 0x08
|
||||
if (zone > 0) {
|
||||
octet = octet | 0x08;
|
||||
}
|
||||
this.writeHexOctet(octet);
|
||||
},
|
||||
|
||||
/**
|
||||
* User data can be 7 bit (default alphabet) data, 8 bit data, or 16 bit
|
||||
* (UCS2) data.
|
||||
@ -7738,6 +7866,9 @@ let StkCommandParamsFactory = {
|
||||
case STK_CMD_POLL_OFF:
|
||||
param = this.processPollOff(cmdDetails, ctlvs);
|
||||
break;
|
||||
case STK_CMD_PROVIDE_LOCAL_INFO:
|
||||
param = this.processProvideLocalInfo(cmdDetails, ctlvs);
|
||||
break;
|
||||
case STK_CMD_SET_UP_EVENT_LIST:
|
||||
param = this.processSetUpEventList(cmdDetails, ctlvs);
|
||||
break;
|
||||
@ -8145,6 +8276,21 @@ let StkCommandParamsFactory = {
|
||||
playTone.isVibrate = (cmdDetails.commandQualifier & 0x01) != 0x00;
|
||||
|
||||
return playTone;
|
||||
},
|
||||
|
||||
/**
|
||||
* Construct a param for Provide Local Information
|
||||
*
|
||||
* @param cmdDetails
|
||||
* The value object of CommandDetails TLV.
|
||||
* @param ctlvs
|
||||
* The all TLVs in this proactive command.
|
||||
*/
|
||||
processProvideLocalInfo: function processProvideLocalInfo(cmdDetails, ctlvs) {
|
||||
let provideLocalInfo = {
|
||||
localInfoType: cmdDetails.commandQualifier
|
||||
};
|
||||
return provideLocalInfo;
|
||||
}
|
||||
};
|
||||
|
||||
@ -8664,6 +8810,24 @@ let ComprehensionTlvHelper = {
|
||||
GsmPDUHelper.writeHexOctet(0x80 | cause);
|
||||
},
|
||||
|
||||
writeDateTimeZoneTlv: function writeDataTimeZoneTlv(date) {
|
||||
GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_DATE_TIME_ZONE);
|
||||
GsmPDUHelper.writeHexOctet(7);
|
||||
GsmPDUHelper.writeTimestamp(date);
|
||||
},
|
||||
|
||||
writeLanguageTlv: function writeLanguageTlv(language) {
|
||||
GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_LANGUAGE);
|
||||
GsmPDUHelper.writeHexOctet(2);
|
||||
|
||||
// ISO 639-1, Alpha-2 code
|
||||
// TS 123.038, clause 6.2.1, GSM 7 bit Default Alphabet
|
||||
GsmPDUHelper.writeHexOctet(
|
||||
PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT].indexOf(language[0]));
|
||||
GsmPDUHelper.writeHexOctet(
|
||||
PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT].indexOf(language[1]));
|
||||
},
|
||||
|
||||
getSizeOfLengthOctets: function getSizeOfLengthOctets(length) {
|
||||
if (length >= 0x10000) {
|
||||
return 4; // 0x83, len_1, len_2, len_3
|
||||
|
@ -82,6 +82,81 @@ add_test_incoming_parcel(null,
|
||||
}
|
||||
);
|
||||
|
||||
// Test Bug 814761: buffer overwritten
|
||||
add_test(function test_incoming_parcel_buffer_overwritten() {
|
||||
let worker = newWorker({
|
||||
postRILMessage: function fakePostRILMessage(data) {
|
||||
// do nothing
|
||||
},
|
||||
postMessage: function fakePostMessage(message) {
|
||||
// do nothing
|
||||
}
|
||||
});
|
||||
|
||||
// A convenient alias.
|
||||
let buf = worker.Buf;
|
||||
|
||||
// Allocate an array of specified size and set each of its elements to value.
|
||||
function calloc(length, value) {
|
||||
let array = new Array(length);
|
||||
for (let i = 0; i < length; i++) {
|
||||
array[i] = value;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
// Do nothing in handleParcel().
|
||||
let request = worker.REQUEST_REGISTRATION_STATE;
|
||||
worker.RIL[request] = null;
|
||||
|
||||
// Prepare two parcels, whose sizes are both smaller than the incoming buffer
|
||||
// size but larger when combined, to trigger the bug.
|
||||
let pA_dataLength = buf.INCOMING_BUFFER_LENGTH / 2;
|
||||
let pA = newIncomingParcel(-1,
|
||||
worker.RESPONSE_TYPE_UNSOLICITED,
|
||||
request,
|
||||
calloc(pA_dataLength, 1));
|
||||
let pA_parcelSize = pA.length - worker.PARCEL_SIZE_SIZE;
|
||||
|
||||
let pB_dataLength = buf.INCOMING_BUFFER_LENGTH * 3 / 4;
|
||||
let pB = newIncomingParcel(-1,
|
||||
worker.RESPONSE_TYPE_UNSOLICITED,
|
||||
request,
|
||||
calloc(pB_dataLength, 1));
|
||||
let pB_parcelSize = pB.length - worker.PARCEL_SIZE_SIZE;
|
||||
|
||||
// First, send an incomplete pA and verifies related data pointer:
|
||||
let p1 = pA.subarray(0, pA.length - 1);
|
||||
worker.onRILMessage(p1);
|
||||
// The parcel should not have been processed.
|
||||
do_check_eq(buf.readAvailable, 0);
|
||||
// buf.currentParcelSize should have been set because incoming data has more
|
||||
// than 4 octets.
|
||||
do_check_eq(buf.currentParcelSize, pA_parcelSize);
|
||||
// buf.readIncoming should contains remaining unconsumed octets count.
|
||||
do_check_eq(buf.readIncoming, p1.length - worker.PARCEL_SIZE_SIZE);
|
||||
// buf.incomingWriteIndex should be ready to accept the last octet.
|
||||
do_check_eq(buf.incomingWriteIndex, p1.length);
|
||||
|
||||
// Second, send the last octet of pA and whole pB. The Buf should now expand
|
||||
// to cover both pA & pB.
|
||||
let p2 = new Uint8Array(1 + pB.length);
|
||||
p2.set(pA.subarray(pA.length - 1), 0);
|
||||
p2.set(pB, 1);
|
||||
worker.onRILMessage(p2);
|
||||
// The parcels should have been both consumed.
|
||||
do_check_eq(buf.readAvailable, 0);
|
||||
// No parcel data remains.
|
||||
do_check_eq(buf.currentParcelSize, 0);
|
||||
// No parcel data remains.
|
||||
do_check_eq(buf.readIncoming, 0);
|
||||
// The Buf should now expand to cover both pA & pB.
|
||||
do_check_eq(buf.incomingWriteIndex, pA.length + pB.length);
|
||||
|
||||
// end of incoming parcel's trip, let's do next test.
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// Test Buf.readUint8Array.
|
||||
add_test_incoming_parcel(null,
|
||||
function test_buf_readUint8Array(worker) {
|
||||
|
@ -121,6 +121,75 @@ add_test(function test_write_dialling_number() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
/**
|
||||
* Verify GsmPDUHelper.writeTimestamp
|
||||
*/
|
||||
add_test(function test_write_timestamp() {
|
||||
let worker = newUint8Worker();
|
||||
let helper = worker.GsmPDUHelper;
|
||||
|
||||
// current date
|
||||
let dateInput = new Date();
|
||||
let dateOutput = new Date();
|
||||
helper.writeTimestamp(dateInput);
|
||||
dateOutput.setTime(helper.readTimestamp());
|
||||
|
||||
do_check_eq(dateInput.getFullYear(), dateOutput.getFullYear());
|
||||
do_check_eq(dateInput.getMonth(), dateOutput.getMonth());
|
||||
do_check_eq(dateInput.getDate(), dateOutput.getDate());
|
||||
do_check_eq(dateInput.getHours(), dateOutput.getHours());
|
||||
do_check_eq(dateInput.getMinutes(), dateOutput.getMinutes());
|
||||
do_check_eq(dateInput.getSeconds(), dateOutput.getSeconds());
|
||||
do_check_eq(dateInput.getTimezoneOffset(), dateOutput.getTimezoneOffset());
|
||||
|
||||
// 2034-01-23 12:34:56 -0800 GMT
|
||||
let time = Date.UTC(2034, 1, 23, 12, 34, 56);
|
||||
time = time - (8 * 60 * 60 * 1000);
|
||||
dateInput.setTime(time);
|
||||
helper.writeTimestamp(dateInput);
|
||||
dateOutput.setTime(helper.readTimestamp());
|
||||
|
||||
do_check_eq(dateInput.getFullYear(), dateOutput.getFullYear());
|
||||
do_check_eq(dateInput.getMonth(), dateOutput.getMonth());
|
||||
do_check_eq(dateInput.getDate(), dateOutput.getDate());
|
||||
do_check_eq(dateInput.getHours(), dateOutput.getHours());
|
||||
do_check_eq(dateInput.getMinutes(), dateOutput.getMinutes());
|
||||
do_check_eq(dateInput.getSeconds(), dateOutput.getSeconds());
|
||||
do_check_eq(dateInput.getTimezoneOffset(), dateOutput.getTimezoneOffset());
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
/**
|
||||
* Verify GsmPDUHelper.octectToBCD and GsmPDUHelper.BCDToOctet
|
||||
*/
|
||||
add_test(function test_octect_BCD() {
|
||||
let worker = newUint8Worker();
|
||||
let helper = worker.GsmPDUHelper;
|
||||
|
||||
// 23
|
||||
let number = 23;
|
||||
let octet = helper.BCDToOctet(number);
|
||||
do_check_eq(helper.octetToBCD(octet), number);
|
||||
|
||||
// 56
|
||||
number = 56;
|
||||
octet = helper.BCDToOctet(number);
|
||||
do_check_eq(helper.octetToBCD(octet), number);
|
||||
|
||||
// 0x23
|
||||
octet = 0x23;
|
||||
number = helper.octetToBCD(octet);
|
||||
do_check_eq(helper.BCDToOctet(number), octet);
|
||||
|
||||
// 0x56
|
||||
octet = 0x56;
|
||||
number = helper.octetToBCD(octet);
|
||||
do_check_eq(helper.BCDToOctet(number), octet);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
/**
|
||||
* Verify RIL.isICCServiceAvailable.
|
||||
*/
|
||||
@ -582,3 +651,51 @@ add_test(function test_stk_proactive_command_more_time() {
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
/**
|
||||
* Verify Proactive Command : Provide Local Information
|
||||
*/
|
||||
add_test(function test_stk_proactive_command_provide_local_information() {
|
||||
let worker = newUint8Worker();
|
||||
let pduHelper = worker.GsmPDUHelper;
|
||||
let berHelper = worker.BerTlvHelper;
|
||||
let stkHelper = worker.StkProactiveCmdHelper;
|
||||
|
||||
// Verify IMEI
|
||||
let local_info_1 = [
|
||||
0xD0,
|
||||
0x09,
|
||||
0x81, 0x03, 0x01, 0x26, 0x01,
|
||||
0x82, 0x02, 0x81, 0x82];
|
||||
|
||||
for (let i = 0; i < local_info_1.length; i++) {
|
||||
pduHelper.writeHexOctet(local_info_1[i]);
|
||||
}
|
||||
|
||||
let berTlv = berHelper.decode(local_info_1.length);
|
||||
let ctlvs = berTlv.value;
|
||||
let tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_COMMAND_DETAILS, ctlvs);
|
||||
do_check_eq(tlv.value.commandNumber, 0x01);
|
||||
do_check_eq(tlv.value.typeOfCommand, STK_CMD_PROVIDE_LOCAL_INFO);
|
||||
do_check_eq(tlv.value.commandQualifier, STK_LOCAL_INFO_IMEI);
|
||||
|
||||
// Verify Date and Time Zone
|
||||
let local_info_2 = [
|
||||
0xD0,
|
||||
0x09,
|
||||
0x81, 0x03, 0x01, 0x26, 0x03,
|
||||
0x82, 0x02, 0x81, 0x82];
|
||||
|
||||
for (let i = 0; i < local_info_2.length; i++) {
|
||||
pduHelper.writeHexOctet(local_info_2[i]);
|
||||
}
|
||||
|
||||
berTlv = berHelper.decode(local_info_2.length);
|
||||
ctlvs = berTlv.value;
|
||||
tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_COMMAND_DETAILS, ctlvs);
|
||||
do_check_eq(tlv.value.commandNumber, 0x01);
|
||||
do_check_eq(tlv.value.typeOfCommand, STK_CMD_PROVIDE_LOCAL_INFO);
|
||||
do_check_eq(tlv.value.commandQualifier, STK_LOCAL_INFO_DATE_TIME_ZONE);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -84,7 +84,7 @@ public:
|
||||
}
|
||||
private:
|
||||
uint16_t mEnum;
|
||||
void bool_conversion_helper() {};
|
||||
void bool_conversion_helper() {}
|
||||
public:
|
||||
// Allow boolean conversion with no numeric conversion
|
||||
typedef void (WSType::*bool_type)();
|
||||
|
@ -39,6 +39,18 @@
|
||||
#include <emmintrin.h> // ARCH_CPU_X86_FAMILY was defined in build/config.h
|
||||
#endif
|
||||
|
||||
#if defined(SK_CPU_LENDIAN)
|
||||
#define R_OFFSET_IDX 0
|
||||
#define G_OFFSET_IDX 1
|
||||
#define B_OFFSET_IDX 2
|
||||
#define A_OFFSET_IDX 3
|
||||
#else
|
||||
#define R_OFFSET_IDX 3
|
||||
#define G_OFFSET_IDX 2
|
||||
#define B_OFFSET_IDX 1
|
||||
#define A_OFFSET_IDX 0
|
||||
#endif
|
||||
|
||||
namespace skia {
|
||||
|
||||
namespace {
|
||||
@ -162,11 +174,11 @@ void ConvolveHorizontally(const unsigned char* src_data,
|
||||
int accum[4] = {0};
|
||||
for (int filter_x = 0; filter_x < filter_length; filter_x++) {
|
||||
ConvolutionFilter1D::Fixed cur_filter = filter_values[filter_x];
|
||||
accum[0] += cur_filter * row_to_filter[filter_x * 4 + 0];
|
||||
accum[1] += cur_filter * row_to_filter[filter_x * 4 + 1];
|
||||
accum[2] += cur_filter * row_to_filter[filter_x * 4 + 2];
|
||||
accum[0] += cur_filter * row_to_filter[filter_x * 4 + R_OFFSET_IDX];
|
||||
accum[1] += cur_filter * row_to_filter[filter_x * 4 + G_OFFSET_IDX];
|
||||
accum[2] += cur_filter * row_to_filter[filter_x * 4 + B_OFFSET_IDX];
|
||||
if (has_alpha)
|
||||
accum[3] += cur_filter * row_to_filter[filter_x * 4 + 3];
|
||||
accum[3] += cur_filter * row_to_filter[filter_x * 4 + A_OFFSET_IDX];
|
||||
}
|
||||
|
||||
// Bring this value back in range. All of the filter scaling factors
|
||||
@ -178,11 +190,11 @@ void ConvolveHorizontally(const unsigned char* src_data,
|
||||
accum[3] >>= ConvolutionFilter1D::kShiftBits;
|
||||
|
||||
// Store the new pixel.
|
||||
out_row[out_x * 4 + 0] = ClampTo8(accum[0]);
|
||||
out_row[out_x * 4 + 1] = ClampTo8(accum[1]);
|
||||
out_row[out_x * 4 + 2] = ClampTo8(accum[2]);
|
||||
out_row[out_x * 4 + R_OFFSET_IDX] = ClampTo8(accum[0]);
|
||||
out_row[out_x * 4 + G_OFFSET_IDX] = ClampTo8(accum[1]);
|
||||
out_row[out_x * 4 + B_OFFSET_IDX] = ClampTo8(accum[2]);
|
||||
if (has_alpha)
|
||||
out_row[out_x * 4 + 3] = ClampTo8(accum[3]);
|
||||
out_row[out_x * 4 + A_OFFSET_IDX] = ClampTo8(accum[3]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,11 +221,15 @@ void ConvolveVertically(const ConvolutionFilter1D::Fixed* filter_values,
|
||||
int accum[4] = {0};
|
||||
for (int filter_y = 0; filter_y < filter_length; filter_y++) {
|
||||
ConvolutionFilter1D::Fixed cur_filter = filter_values[filter_y];
|
||||
accum[0] += cur_filter * source_data_rows[filter_y][byte_offset + 0];
|
||||
accum[1] += cur_filter * source_data_rows[filter_y][byte_offset + 1];
|
||||
accum[2] += cur_filter * source_data_rows[filter_y][byte_offset + 2];
|
||||
accum[0] += cur_filter
|
||||
* source_data_rows[filter_y][byte_offset + R_OFFSET_IDX];
|
||||
accum[1] += cur_filter
|
||||
* source_data_rows[filter_y][byte_offset + G_OFFSET_IDX];
|
||||
accum[2] += cur_filter
|
||||
* source_data_rows[filter_y][byte_offset + B_OFFSET_IDX];
|
||||
if (has_alpha)
|
||||
accum[3] += cur_filter * source_data_rows[filter_y][byte_offset + 3];
|
||||
accum[3] += cur_filter
|
||||
* source_data_rows[filter_y][byte_offset + A_OFFSET_IDX];
|
||||
}
|
||||
|
||||
// Bring this value back in range. All of the filter scaling factors
|
||||
@ -225,9 +241,9 @@ void ConvolveVertically(const ConvolutionFilter1D::Fixed* filter_values,
|
||||
accum[3] >>= ConvolutionFilter1D::kShiftBits;
|
||||
|
||||
// Store the new pixel.
|
||||
out_row[byte_offset + 0] = ClampTo8(accum[0]);
|
||||
out_row[byte_offset + 1] = ClampTo8(accum[1]);
|
||||
out_row[byte_offset + 2] = ClampTo8(accum[2]);
|
||||
out_row[byte_offset + R_OFFSET_IDX] = ClampTo8(accum[0]);
|
||||
out_row[byte_offset + G_OFFSET_IDX] = ClampTo8(accum[1]);
|
||||
out_row[byte_offset + B_OFFSET_IDX] = ClampTo8(accum[2]);
|
||||
if (has_alpha) {
|
||||
unsigned char alpha = ClampTo8(accum[3]);
|
||||
|
||||
@ -238,15 +254,15 @@ void ConvolveVertically(const ConvolutionFilter1D::Fixed* filter_values,
|
||||
// values) when the resulting bitmap is drawn to the screen.
|
||||
//
|
||||
// We only need to do this when generating the final output row (here).
|
||||
int max_color_channel = NS_MAX(out_row[byte_offset + 0],
|
||||
NS_MAX(out_row[byte_offset + 1], out_row[byte_offset + 2]));
|
||||
int max_color_channel = NS_MAX(out_row[byte_offset + R_OFFSET_IDX],
|
||||
NS_MAX(out_row[byte_offset + G_OFFSET_IDX], out_row[byte_offset + B_OFFSET_IDX]));
|
||||
if (alpha < max_color_channel)
|
||||
out_row[byte_offset + 3] = max_color_channel;
|
||||
out_row[byte_offset + A_OFFSET_IDX] = max_color_channel;
|
||||
else
|
||||
out_row[byte_offset + 3] = alpha;
|
||||
out_row[byte_offset + A_OFFSET_IDX] = alpha;
|
||||
} else {
|
||||
// No alpha channel, the image is opaque.
|
||||
out_row[byte_offset + 3] = 0xff;
|
||||
out_row[byte_offset + A_OFFSET_IDX] = 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -142,6 +142,7 @@ EXPORTS_mozilla/layers =\
|
||||
RenderTrace.h \
|
||||
SharedImageUtils.h \
|
||||
ShmemYCbCrImage.h \
|
||||
TaskThrottler.h \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS += \
|
||||
@ -161,6 +162,7 @@ CPPSRCS += \
|
||||
ShadowLayerParent.cpp \
|
||||
ShadowLayersParent.cpp \
|
||||
ShmemYCbCrImage.cpp \
|
||||
TaskThrottler.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_X11 #{
|
||||
|
@ -967,7 +967,11 @@ void AsyncPanZoomController::RequestContentRepaint() {
|
||||
// This message is compressed, so fire whether or not we already have a paint
|
||||
// queued up. We need to know whether or not a paint was requested anyways,
|
||||
// for the purposes of content calling window.scrollTo().
|
||||
mGeckoContentController->RequestContentRepaint(mFrameMetrics);
|
||||
mPaintThrottler.PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(mGeckoContentController.get(),
|
||||
&GeckoContentController::RequestContentRepaint,
|
||||
mFrameMetrics));
|
||||
mLastPaintRequestMetrics = mFrameMetrics;
|
||||
mWaitingForContentToPaint = true;
|
||||
|
||||
@ -1081,6 +1085,8 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
|
||||
void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFrame, bool aIsFirstPaint) {
|
||||
MonitorAutoLock monitor(mMonitor);
|
||||
|
||||
mPaintThrottler.TaskComplete();
|
||||
|
||||
mLastContentPaintMetrics = aViewportFrame;
|
||||
|
||||
if (mWaitingForContentToPaint) {
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "InputData.h"
|
||||
#include "Axis.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "TaskThrottler.h"
|
||||
|
||||
#include "base/message_loop.h"
|
||||
|
||||
@ -458,6 +459,7 @@ private:
|
||||
void SetState(PanZoomState aState);
|
||||
|
||||
nsRefPtr<CompositorParent> mCompositorParent;
|
||||
TaskThrottler mPaintThrottler;
|
||||
nsRefPtr<GeckoContentController> mGeckoContentController;
|
||||
nsRefPtr<GestureEventListener> mGestureEventListener;
|
||||
|
||||
|
@ -39,12 +39,16 @@ public:
|
||||
Transaction()
|
||||
: mSwapRequired(false)
|
||||
, mOpen(false)
|
||||
, mRotationChanged(false)
|
||||
{}
|
||||
|
||||
void Begin(const nsIntRect& aTargetBounds, ScreenRotation aRotation)
|
||||
{
|
||||
mOpen = true;
|
||||
mTargetBounds = aTargetBounds;
|
||||
if (aRotation != mTargetRotation) {
|
||||
mRotationChanged = true;
|
||||
}
|
||||
mTargetRotation = aRotation;
|
||||
}
|
||||
|
||||
@ -86,11 +90,15 @@ public:
|
||||
mMutants.clear();
|
||||
mOpen = false;
|
||||
mSwapRequired = false;
|
||||
mRotationChanged = false;
|
||||
}
|
||||
|
||||
bool Empty() const {
|
||||
return mCset.empty() && mPaints.empty() && mMutants.empty();
|
||||
}
|
||||
bool RotationChanged() const {
|
||||
return mRotationChanged;
|
||||
}
|
||||
bool Finished() const { return !mOpen && Empty(); }
|
||||
|
||||
EditVector mCset;
|
||||
@ -103,6 +111,7 @@ public:
|
||||
|
||||
private:
|
||||
bool mOpen;
|
||||
bool mRotationChanged;
|
||||
|
||||
// disabled
|
||||
Transaction(const Transaction&);
|
||||
@ -285,8 +294,8 @@ ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies)
|
||||
|
||||
AutoTxnEnd _(mTxn);
|
||||
|
||||
if (mTxn->Empty()) {
|
||||
MOZ_LAYERS_LOG(("[LayersForwarder] 0-length cset (?), skipping Update()"));
|
||||
if (mTxn->Empty() && !mTxn->RotationChanged()) {
|
||||
MOZ_LAYERS_LOG(("[LayersForwarder] 0-length cset (?) and no rotation event, skipping Update()"));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
49
gfx/layers/ipc/TaskThrottler.cpp
Normal file
49
gfx/layers/ipc/TaskThrottler.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*- */
|
||||
/* vim: set sw=2 sts=2 ts=8 et tw=80 : */
|
||||
/* 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 "base/basictypes.h"
|
||||
#include "base/message_loop.h"
|
||||
#include "TaskThrottler.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
TaskThrottler::TaskThrottler()
|
||||
: mOutstanding(false)
|
||||
, mQueuedTask(nullptr)
|
||||
{ }
|
||||
|
||||
void
|
||||
TaskThrottler::PostTask(const tracked_objects::Location& aLocation,
|
||||
CancelableTask* aTask)
|
||||
{
|
||||
aTask->SetBirthPlace(aLocation);
|
||||
|
||||
if (mOutstanding) {
|
||||
if (mQueuedTask) {
|
||||
mQueuedTask->Cancel();
|
||||
}
|
||||
mQueuedTask = aTask;
|
||||
} else {
|
||||
aTask->Run();
|
||||
delete aTask;
|
||||
mOutstanding = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TaskThrottler::TaskComplete()
|
||||
{
|
||||
if (mQueuedTask) {
|
||||
mQueuedTask->Run();
|
||||
mQueuedTask = nullptr;
|
||||
} else {
|
||||
mOutstanding = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
56
gfx/layers/ipc/TaskThrottler.h
Normal file
56
gfx/layers/ipc/TaskThrottler.h
Normal file
@ -0,0 +1,56 @@
|
||||
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2; -*- */
|
||||
/* vim: set sw=4 ts=8 et tw=80 : */
|
||||
/* 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 mozilla_dom_TaskThrottler_h
|
||||
#define mozilla_dom_TaskThrottler_h
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
class CancelableTask;
|
||||
namespace tracked_objects {
|
||||
class Location;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
/** The TaskThrottler prevents update event overruns. It is used in cases where
|
||||
* you're sending an async message and waiting for a reply. You need to call
|
||||
* PostTask to queue a task and TaskComplete when you get a response.
|
||||
*
|
||||
* The call to TaskComplete will run the recent task posted since the last
|
||||
* request was sent, if any. This means that at any time there can be at most 1
|
||||
* outstanding request being processed and at most 1 queued behind it.
|
||||
*
|
||||
* This is used in the context of repainting a scrollable region. While another
|
||||
* process is painting you might get several updates from the UI thread but when
|
||||
* the paint is complete you want to send the most recent.
|
||||
*/
|
||||
|
||||
class TaskThrottler {
|
||||
public:
|
||||
TaskThrottler();
|
||||
|
||||
/** Post a task to be run as soon as there are no outstanding tasks.
|
||||
*
|
||||
* @param aLocation Use the macro FROM_HERE
|
||||
* @param aTask Ownership of this object is transferred to TaskThrottler
|
||||
* which will delete it when it is either run or becomes
|
||||
* obsolete or the TaskThrottler is destructed.
|
||||
*/
|
||||
void PostTask(const tracked_objects::Location& aLocation,
|
||||
CancelableTask* aTask);
|
||||
void TaskComplete();
|
||||
|
||||
private:
|
||||
bool mOutstanding;
|
||||
nsAutoPtr<CancelableTask> mQueuedTask;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // mozilla_dom_TaskThrottler_h
|
@ -94,7 +94,7 @@
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(SK_CPU_BENDIAN) && !defined(SK_CPU_LENDIAN)
|
||||
#if defined (__ppc__) || defined(__ppc64__)
|
||||
#if defined (__ppc__) || defined(__PPC__) || defined(__ppc64__) || defined(__PPC64__)
|
||||
#define SK_CPU_BENDIAN
|
||||
#else
|
||||
#define SK_CPU_LENDIAN
|
||||
|
@ -196,6 +196,7 @@ FT2FontEntry::CreateFontEntry(const gfxProxyFontEntry &aProxyEntry,
|
||||
fe->mItalic = aProxyEntry.mItalic;
|
||||
fe->mWeight = aProxyEntry.mWeight;
|
||||
fe->mStretch = aProxyEntry.mStretch;
|
||||
fe->mIsUserFont = true;
|
||||
}
|
||||
return fe;
|
||||
}
|
||||
|
@ -82,8 +82,14 @@ gfxCharacterMap::NotifyReleased()
|
||||
delete this;
|
||||
}
|
||||
|
||||
gfxFontEntry::~gfxFontEntry()
|
||||
gfxFontEntry::~gfxFontEntry()
|
||||
{
|
||||
// For downloaded fonts, we need to tell the user font cache that this
|
||||
// entry is being deleted.
|
||||
if (!mIsProxy && IsUserFont() && !IsLocalUserFont()) {
|
||||
gfxUserFontSet::UserFontCache::ForgetFont(this);
|
||||
}
|
||||
|
||||
if (mSVGGlyphs) {
|
||||
delete mSVGGlyphs;
|
||||
}
|
||||
@ -1238,6 +1244,11 @@ gfxFontCache::gfxFontCache()
|
||||
|
||||
gfxFontCache::~gfxFontCache()
|
||||
{
|
||||
// Ensure the user font cache releases its references to font entries,
|
||||
// so they aren't kept alive after the font instances and font-list
|
||||
// have been shut down.
|
||||
gfxUserFontSet::UserFontCache::Shutdown();
|
||||
|
||||
if (mWordCacheExpirationTimer) {
|
||||
mWordCacheExpirationTimer->Cancel();
|
||||
mWordCacheExpirationTimer = nullptr;
|
||||
|
@ -1504,6 +1504,15 @@ gfxFcFontSet::SortPreferredFonts(bool &aWaitForUserFont)
|
||||
for (uint32_t f = 0; f < familyFonts->Length(); ++f) {
|
||||
FcPattern *font = familyFonts->ElementAt(f);
|
||||
|
||||
// Fix up the family name of user-font patterns, as the same
|
||||
// font entry may be used (via the UserFontCache) for multiple
|
||||
// CSS family names
|
||||
if (isUserFont) {
|
||||
font = FcPatternDuplicate(font);
|
||||
FcPatternDel(font, FC_FAMILY);
|
||||
FcPatternAddString(font, FC_FAMILY, family);
|
||||
}
|
||||
|
||||
// User fonts are already filtered by slant (but not size) in
|
||||
// mUserFontSet->FindFontEntry().
|
||||
if (!isUserFont && !SlantIsAcceptable(font, requestedSlant))
|
||||
@ -1524,7 +1533,12 @@ gfxFcFontSet::SortPreferredFonts(bool &aWaitForUserFont)
|
||||
// FcFontSetDestroy will remove a reference but FcFontSetAdd
|
||||
// does _not_ take a reference!
|
||||
if (FcFontSetAdd(fontSet, font)) {
|
||||
FcPatternReference(font);
|
||||
// We don't add a reference here for user fonts, because we're
|
||||
// using a local clone of the pattern (see above) in order to
|
||||
// override the family name
|
||||
if (!isUserFont) {
|
||||
FcPatternReference(font);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "prlong.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
#include "woff.h"
|
||||
|
||||
@ -406,6 +408,7 @@ StoreUserFontData(gfxFontEntry* aFontEntry, gfxProxyFontEntry* aProxy,
|
||||
userFontData->mLocalName = src.mLocalName;
|
||||
} else {
|
||||
userFontData->mURI = src.mURI;
|
||||
userFontData->mPrincipal = aProxy->mPrincipal;
|
||||
}
|
||||
userFontData->mFormat = src.mFormatFlags;
|
||||
userFontData->mRealName = aOriginalName;
|
||||
@ -559,48 +562,65 @@ gfxUserFontSet::LoadNext(gfxProxyFontEntry *aProxyEntry)
|
||||
if (gfxPlatform::GetPlatform()->IsFontFormatSupported(currSrc.mURI,
|
||||
currSrc.mFormatFlags)) {
|
||||
|
||||
nsresult rv;
|
||||
bool loadDoesntSpin = false;
|
||||
rv = NS_URIChainHasFlags(currSrc.mURI,
|
||||
nsIProtocolHandler::URI_SYNC_LOAD_IS_OK,
|
||||
&loadDoesntSpin);
|
||||
nsIPrincipal *principal = nullptr;
|
||||
nsresult rv = CheckFontLoad(&currSrc, &principal);
|
||||
|
||||
if (NS_SUCCEEDED(rv) && loadDoesntSpin) {
|
||||
uint8_t *buffer = nullptr;
|
||||
uint32_t bufferLength = 0;
|
||||
|
||||
// sync load font immediately
|
||||
rv = SyncLoadFontData(aProxyEntry, &currSrc, buffer,
|
||||
bufferLength);
|
||||
|
||||
if (NS_SUCCEEDED(rv) &&
|
||||
LoadFont(aProxyEntry, buffer, bufferLength)) {
|
||||
if (NS_SUCCEEDED(rv) && principal != nullptr) {
|
||||
// see if we have an existing entry for this source
|
||||
gfxFontEntry *fe =
|
||||
UserFontCache::GetFont(currSrc.mURI, principal,
|
||||
aProxyEntry);
|
||||
if (fe) {
|
||||
ReplaceFontEntry(aProxyEntry, fe);
|
||||
return STATUS_LOADED;
|
||||
} else {
|
||||
LogMessage(aProxyEntry, "font load failed",
|
||||
nsIScriptError::errorFlag, rv);
|
||||
}
|
||||
|
||||
} else {
|
||||
// otherwise load font async
|
||||
rv = StartLoad(aProxyEntry, &currSrc);
|
||||
bool loadOK = NS_SUCCEEDED(rv);
|
||||
// record the principal returned by CheckFontLoad,
|
||||
// for use when creating a channel
|
||||
// and when caching the loaded entry
|
||||
aProxyEntry->mPrincipal = principal;
|
||||
|
||||
if (loadOK) {
|
||||
#ifdef PR_LOGGING
|
||||
if (LOG_ENABLED()) {
|
||||
nsAutoCString fontURI;
|
||||
currSrc.mURI->GetSpec(fontURI);
|
||||
LOG(("userfonts (%p) [src %d] loading uri: (%s) for (%s)\n",
|
||||
this, aProxyEntry->mSrcIndex, fontURI.get(),
|
||||
NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get()));
|
||||
bool loadDoesntSpin = false;
|
||||
rv = NS_URIChainHasFlags(currSrc.mURI,
|
||||
nsIProtocolHandler::URI_SYNC_LOAD_IS_OK,
|
||||
&loadDoesntSpin);
|
||||
if (NS_SUCCEEDED(rv) && loadDoesntSpin) {
|
||||
uint8_t *buffer = nullptr;
|
||||
uint32_t bufferLength = 0;
|
||||
|
||||
// sync load font immediately
|
||||
rv = SyncLoadFontData(aProxyEntry, &currSrc,
|
||||
buffer, bufferLength);
|
||||
if (NS_SUCCEEDED(rv) &&
|
||||
(fe = LoadFont(aProxyEntry, buffer, bufferLength))) {
|
||||
UserFontCache::CacheFont(fe);
|
||||
return STATUS_LOADED;
|
||||
} else {
|
||||
LogMessage(aProxyEntry, "font load failed",
|
||||
nsIScriptError::errorFlag, rv);
|
||||
}
|
||||
#endif
|
||||
return STATUS_LOADING;
|
||||
} else {
|
||||
LogMessage(aProxyEntry, "download failed",
|
||||
nsIScriptError::errorFlag, rv);
|
||||
// otherwise load font async
|
||||
rv = StartLoad(aProxyEntry, &currSrc);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
#ifdef PR_LOGGING
|
||||
if (LOG_ENABLED()) {
|
||||
nsAutoCString fontURI;
|
||||
currSrc.mURI->GetSpec(fontURI);
|
||||
LOG(("userfonts (%p) [src %d] loading uri: (%s) for (%s)\n",
|
||||
this, aProxyEntry->mSrcIndex, fontURI.get(),
|
||||
NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get()));
|
||||
}
|
||||
#endif
|
||||
return STATUS_LOADING;
|
||||
} else {
|
||||
LogMessage(aProxyEntry, "download failed",
|
||||
nsIScriptError::errorFlag, rv);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LogMessage(aProxyEntry, "download not allowed",
|
||||
nsIScriptError::errorFlag, rv);
|
||||
}
|
||||
} else {
|
||||
// We don't log a warning to the web console yet,
|
||||
@ -752,6 +772,7 @@ gfxUserFontSet::LoadFont(gfxProxyFontEntry *aProxy,
|
||||
uint32_t(mGeneration)));
|
||||
}
|
||||
#endif
|
||||
UserFontCache::CacheFont(fe);
|
||||
ReplaceFontEntry(aProxy, fe);
|
||||
} else {
|
||||
#ifdef PR_LOGGING
|
||||
@ -778,3 +799,94 @@ gfxUserFontSet::GetFamily(const nsAString& aFamilyName) const
|
||||
return mFontFamilies.GetWeak(key);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// gfxUserFontSet::UserFontCache - re-use platform font entries for user fonts
|
||||
// across pages/fontsets rather than instantiating new platform fonts.
|
||||
//
|
||||
// Entries are added to this cache when a platform font is instantiated from
|
||||
// downloaded data, and removed when the platform font entry is destroyed.
|
||||
// We don't need to use a timed expiration scheme here because the gfxFontEntry
|
||||
// for a downloaded font will be kept alive by its corresponding gfxFont
|
||||
// instance(s) until they are deleted, and *that* happens using an expiration
|
||||
// tracker (gfxFontCache). The result is that the downloaded font instances
|
||||
// recorded here will persist between pages and can get reused (provided the
|
||||
// source URI and principal match, of course).
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsTHashtable<gfxUserFontSet::UserFontCache::Entry>*
|
||||
gfxUserFontSet::UserFontCache::sUserFonts = nullptr;
|
||||
|
||||
bool
|
||||
gfxUserFontSet::UserFontCache::Entry::KeyEquals(const KeyTypePointer aKey) const
|
||||
{
|
||||
bool equal;
|
||||
if (NS_FAILED(mURI->Equals(aKey->mURI, &equal)) || !equal) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NS_FAILED(mPrincipal->Equals(aKey->mPrincipal, &equal)) || !equal) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const gfxFontEntry *fe = aKey->mFontEntry;
|
||||
if (mFontEntry->mItalic != fe->mItalic ||
|
||||
mFontEntry->mWeight != fe->mWeight ||
|
||||
mFontEntry->mStretch != fe->mStretch ||
|
||||
mFontEntry->mFeatureSettings != fe->mFeatureSettings ||
|
||||
mFontEntry->mLanguageOverride != fe->mLanguageOverride) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
gfxUserFontSet::UserFontCache::CacheFont(gfxFontEntry *aFontEntry)
|
||||
{
|
||||
if (!sUserFonts) {
|
||||
sUserFonts = new nsTHashtable<Entry>;
|
||||
sUserFonts->Init();
|
||||
}
|
||||
|
||||
gfxUserFontData *data = aFontEntry->mUserFontData;
|
||||
sUserFonts->PutEntry(Key(data->mURI, data->mPrincipal, aFontEntry));
|
||||
}
|
||||
|
||||
void
|
||||
gfxUserFontSet::UserFontCache::ForgetFont(gfxFontEntry *aFontEntry)
|
||||
{
|
||||
if (!sUserFonts) {
|
||||
// if we've already deleted the cache (i.e. during shutdown),
|
||||
// just ignore this
|
||||
return;
|
||||
}
|
||||
|
||||
gfxUserFontData *data = aFontEntry->mUserFontData;
|
||||
sUserFonts->RemoveEntry(Key(data->mURI, data->mPrincipal, aFontEntry));
|
||||
}
|
||||
|
||||
gfxFontEntry*
|
||||
gfxUserFontSet::UserFontCache::GetFont(nsIURI *aSrcURI,
|
||||
nsIPrincipal *aPrincipal,
|
||||
gfxProxyFontEntry *aProxy)
|
||||
{
|
||||
if (!sUserFonts) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Entry* entry = sUserFonts->GetEntry(Key(aSrcURI, aPrincipal, aProxy));
|
||||
if (entry) {
|
||||
return entry->GetFontEntry();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
gfxUserFontSet::UserFontCache::Shutdown()
|
||||
{
|
||||
if (sUserFonts) {
|
||||
delete sUserFonts;
|
||||
sUserFonts = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -14,10 +14,11 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsURIHashKey.h"
|
||||
|
||||
class nsIURI;
|
||||
class gfxMixedFontFamily;
|
||||
class nsFontFaceLoader;
|
||||
|
||||
@ -35,10 +36,9 @@ struct gfxFontFaceSrc {
|
||||
uint32_t mFormatFlags;
|
||||
|
||||
nsString mLocalName; // full font name if local
|
||||
nsCOMPtr<nsIURI> mURI; // uri if url
|
||||
nsCOMPtr<nsIURI> mURI; // uri if url
|
||||
nsCOMPtr<nsIURI> mReferrer; // referrer url if url
|
||||
nsCOMPtr<nsISupports> mOriginPrincipal; // principal if url
|
||||
|
||||
nsCOMPtr<nsIPrincipal> mOriginPrincipal; // principal if url
|
||||
};
|
||||
|
||||
// Subclassed to store platform-specific code cleaned out when font entry is
|
||||
@ -56,6 +56,7 @@ public:
|
||||
|
||||
nsTArray<uint8_t> mMetadata; // woff metadata block (compressed), if any
|
||||
nsCOMPtr<nsIURI> mURI; // URI of the source, if it was url()
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal; // principal for the download, if url()
|
||||
nsString mLocalName; // font name used for the source, if local()
|
||||
nsString mRealName; // original fullname from the font resource
|
||||
uint32_t mSrcIndex; // index in the rule's source list
|
||||
@ -202,10 +203,14 @@ public:
|
||||
bool& aFoundFamily,
|
||||
bool& aNeedsBold,
|
||||
bool& aWaitForUserFont);
|
||||
|
||||
|
||||
// check whether the given source is allowed to be loaded
|
||||
virtual nsresult CheckFontLoad(const gfxFontFaceSrc *aFontFaceSrc,
|
||||
nsIPrincipal **aPrincipal) = 0;
|
||||
|
||||
// initialize the process that loads external font data, which upon
|
||||
// completion will call OnLoadComplete method
|
||||
virtual nsresult StartLoad(gfxProxyFontEntry *aProxy,
|
||||
virtual nsresult StartLoad(gfxProxyFontEntry *aProxy,
|
||||
const gfxFontFaceSrc *aFontFaceSrc) = 0;
|
||||
|
||||
// when download has been completed, pass back data here
|
||||
@ -231,6 +236,104 @@ public:
|
||||
// increment the generation on font load
|
||||
void IncrementGeneration();
|
||||
|
||||
class UserFontCache {
|
||||
public:
|
||||
// Record a loaded user-font in the cache. This requires that the
|
||||
// font-entry's userFontData has been set up already, as it relies
|
||||
// on the URI and Principal recorded there.
|
||||
static void CacheFont(gfxFontEntry *aFontEntry);
|
||||
|
||||
// The given gfxFontEntry is being destroyed, so remove any record that
|
||||
// refers to it.
|
||||
static void ForgetFont(gfxFontEntry *aFontEntry);
|
||||
|
||||
// Return the gfxFontEntry corresponding to a given URI and principal,
|
||||
// and the features of the given proxy, or nullptr if none is available
|
||||
static gfxFontEntry* GetFont(nsIURI *aSrcURI,
|
||||
nsIPrincipal *aPrincipal,
|
||||
gfxProxyFontEntry *aProxy);
|
||||
|
||||
// Clear everything so that we don't leak URIs and Principals.
|
||||
static void Shutdown();
|
||||
|
||||
private:
|
||||
// Key used to look up entries in the user-font cache.
|
||||
// Note that key comparison does *not* use the mFontEntry field
|
||||
// as a whole; it only compares specific fields within the entry
|
||||
// (weight/width/style/features) that could affect font selection
|
||||
// or rendering, and that must match between a font-set's proxy
|
||||
// entry and the corresponding "real" font entry.
|
||||
struct Key {
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
gfxFontEntry *mFontEntry;
|
||||
|
||||
Key(nsIURI* aURI, nsIPrincipal* aPrincipal,
|
||||
gfxFontEntry* aFontEntry)
|
||||
: mURI(aURI),
|
||||
mPrincipal(aPrincipal),
|
||||
mFontEntry(aFontEntry)
|
||||
{ }
|
||||
};
|
||||
|
||||
class Entry : public PLDHashEntryHdr {
|
||||
public:
|
||||
typedef const Key& KeyType;
|
||||
typedef const Key* KeyTypePointer;
|
||||
|
||||
Entry(KeyTypePointer aKey)
|
||||
: mURI(aKey->mURI),
|
||||
mPrincipal(aKey->mPrincipal),
|
||||
mFontEntry(aKey->mFontEntry)
|
||||
{ }
|
||||
|
||||
Entry(const Entry& aOther)
|
||||
: mURI(aOther.mURI),
|
||||
mPrincipal(aOther.mPrincipal),
|
||||
mFontEntry(aOther.mFontEntry)
|
||||
{ }
|
||||
|
||||
~Entry() { }
|
||||
|
||||
bool KeyEquals(const KeyTypePointer aKey) const;
|
||||
|
||||
static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
|
||||
|
||||
static PLDHashNumber HashKey(const KeyTypePointer aKey) {
|
||||
uint32_t principalHash;
|
||||
aKey->mPrincipal->GetHashValue(&principalHash);
|
||||
return mozilla::HashGeneric(principalHash,
|
||||
nsURIHashKey::HashKey(aKey->mURI),
|
||||
HashFeatures(aKey->mFontEntry->mFeatureSettings),
|
||||
( aKey->mFontEntry->mItalic |
|
||||
(aKey->mFontEntry->mWeight << 1) |
|
||||
(aKey->mFontEntry->mStretch << 10) ) ^
|
||||
aKey->mFontEntry->mLanguageOverride);
|
||||
}
|
||||
|
||||
enum { ALLOW_MEMMOVE = false };
|
||||
|
||||
gfxFontEntry* GetFontEntry() const { return mFontEntry; }
|
||||
|
||||
private:
|
||||
static uint32_t
|
||||
HashFeatures(const nsTArray<gfxFontFeature>& aFeatures) {
|
||||
return mozilla::HashBytes(aFeatures.Elements(),
|
||||
aFeatures.Length() * sizeof(gfxFontFeature));
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
|
||||
// The "real" font entry corresponding to this downloaded font.
|
||||
// The font entry MUST notify the cache when it is destroyed
|
||||
// (by calling Forget()).
|
||||
gfxFontEntry *mFontEntry;
|
||||
};
|
||||
|
||||
static nsTHashtable<Entry> *sUserFonts;
|
||||
};
|
||||
|
||||
protected:
|
||||
// for a given proxy font entry, attempt to load the next resource
|
||||
// in the src list
|
||||
@ -247,11 +350,7 @@ protected:
|
||||
virtual nsresult SyncLoadFontData(gfxProxyFontEntry *aFontToLoad,
|
||||
const gfxFontFaceSrc *aFontFaceSrc,
|
||||
uint8_t* &aBuffer,
|
||||
uint32_t &aBufferLength)
|
||||
{
|
||||
// implemented in nsUserFontSet
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
uint32_t &aBufferLength) = 0;
|
||||
|
||||
gfxMixedFontFamily *GetFamily(const nsAString& aName) const;
|
||||
|
||||
@ -320,6 +419,7 @@ public:
|
||||
nsTArray<gfxFontFaceSrc> mSrcList;
|
||||
uint32_t mSrcIndex; // index of loading src item
|
||||
nsFontFaceLoader *mLoader; // current loader for this entry, if any
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
};
|
||||
|
||||
|
||||
|
@ -89,7 +89,7 @@ public:
|
||||
// If we're doing a "size decode", we more or less pass through the image
|
||||
// data, stopping only to scoop out the image dimensions. A size decode
|
||||
// must be enabled by SetSizeDecode() _before_calling Init().
|
||||
bool IsSizeDecode() { return mSizeDecode; };
|
||||
bool IsSizeDecode() { return mSizeDecode; }
|
||||
void SetSizeDecode(bool aSizeDecode)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(!mInitialized, "Can't set size decode after Init()!");
|
||||
@ -104,10 +104,10 @@ public:
|
||||
uint32_t GetCompleteFrameCount() { return mInFrame ? mFrameCount - 1 : mFrameCount; }
|
||||
|
||||
// Error tracking
|
||||
bool HasError() { return HasDataError() || HasDecoderError(); };
|
||||
bool HasDataError() { return mDataError; };
|
||||
bool HasDecoderError() { return NS_FAILED(mFailCode); };
|
||||
nsresult GetDecoderError() { return mFailCode; };
|
||||
bool HasError() { return HasDataError() || HasDecoderError(); }
|
||||
bool HasDataError() { return mDataError; }
|
||||
bool HasDecoderError() { return NS_FAILED(mFailCode); }
|
||||
nsresult GetDecoderError() { return mFailCode; }
|
||||
void PostResizeError() { PostDataError(); }
|
||||
bool GetDecodeDone() const {
|
||||
return mDecodeDone;
|
||||
|
@ -114,7 +114,7 @@ public:
|
||||
imgStatusTracker& GetStatusTracker();
|
||||
|
||||
// Get the current principal of the image. No AddRefing.
|
||||
inline nsIPrincipal* GetPrincipal() const { return mPrincipal.get(); };
|
||||
inline nsIPrincipal* GetPrincipal() const { return mPrincipal.get(); }
|
||||
|
||||
// Resize the cache entry to 0 if it exists
|
||||
void ResetCacheEntry();
|
||||
|
@ -114,7 +114,7 @@ public:
|
||||
// with its status. Weak pointers.
|
||||
void AddConsumer(imgRequestProxy* aConsumer);
|
||||
bool RemoveConsumer(imgRequestProxy* aConsumer, nsresult aStatus);
|
||||
size_t ConsumerCount() const { return mConsumers.Length(); };
|
||||
size_t ConsumerCount() const { return mConsumers.Length(); }
|
||||
|
||||
// This is intentionally non-general because its sole purpose is to support an
|
||||
// some obscure network priority logic in imgRequest. That stuff could probably
|
||||
@ -190,8 +190,8 @@ public:
|
||||
void ClearRequest();
|
||||
|
||||
// Weak pointer getters - no AddRefs.
|
||||
inline mozilla::image::Image* GetImage() const { return mImage; };
|
||||
inline imgRequest* GetRequest() const { return mRequest; };
|
||||
inline mozilla::image::Image* GetImage() const { return mImage; }
|
||||
inline imgRequest* GetRequest() const { return mRequest; }
|
||||
|
||||
inline imgIDecoderObserver* GetDecoderObserver() { return mTrackerObserver.get(); }
|
||||
|
||||
|
@ -24,8 +24,6 @@
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIMemory.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "pratom.h"
|
||||
#include "prmem.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsTextFormatter.h"
|
||||
#include "nsIErrorService.h"
|
||||
|
@ -231,29 +231,6 @@ public:
|
||||
correctDeltas(4, 4);
|
||||
}
|
||||
|
||||
uint32_t *getPoolSpace(uint32_t insn, uint32_t constant, bool isReusable = false)
|
||||
{
|
||||
flushIfNoSpaceFor(4, 4);
|
||||
|
||||
m_loadOffsets.append(AssemblerBuffer::size());
|
||||
if (isReusable)
|
||||
for (int i = 0; i < m_numConsts; ++i) {
|
||||
if (m_mask[i] == ReusableConst && m_pool[i] == constant) {
|
||||
AssemblerBuffer::putInt(AssemblerType::patchConstantPoolLoad(insn, i));
|
||||
correctDeltas(4);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_pool[m_numConsts] = constant;
|
||||
m_mask[m_numConsts] = static_cast<char>(isReusable ? ReusableConst : UniqueConst);
|
||||
|
||||
AssemblerBuffer::putInt(AssemblerType::patchConstantPoolLoad(insn, m_numConsts));
|
||||
++m_numConsts;
|
||||
|
||||
correctDeltas(4, 4);
|
||||
}
|
||||
|
||||
void putIntWithConstantDouble(uint32_t insn, double constant)
|
||||
{
|
||||
flushIfNoSpaceFor(4, 8);
|
||||
|
@ -304,7 +304,7 @@ struct ClosureInfo
|
||||
ffi_closure_free(closure);
|
||||
if (errResult)
|
||||
js_free(errResult);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
bool IsCTypesGlobal(JSObject* obj);
|
||||
|
@ -135,7 +135,7 @@ class BailoutClosure
|
||||
|
||||
void constructFrame() {
|
||||
guards_.construct();
|
||||
};
|
||||
}
|
||||
InvokeArgsGuard *argsGuard() {
|
||||
return &guards_.ref().iag;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ class BitSet : private TempObject
|
||||
private:
|
||||
BitSet(unsigned int max) :
|
||||
max_(max),
|
||||
bits_(NULL) {};
|
||||
bits_(NULL) {}
|
||||
|
||||
unsigned int max_;
|
||||
uint32_t *bits_;
|
||||
|
@ -53,7 +53,7 @@ class FixedList
|
||||
const T &operator [](size_t index) const {
|
||||
JS_ASSERT(index < length_);
|
||||
return list_[index];
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ion
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "IonAnalysis.h"
|
||||
#include "IonBuilder.h"
|
||||
#include "Lowering.h"
|
||||
#include "MIRGraph.h"
|
||||
#include "Ion.h"
|
||||
#include "IonAnalysis.h"
|
||||
@ -5243,7 +5244,7 @@ IonBuilder::jsop_getelem_dense()
|
||||
MDefinition *obj = current->pop();
|
||||
|
||||
JSValueType knownType = JSVAL_TYPE_UNKNOWN;
|
||||
if (!needsHoleCheck && !barrier) {
|
||||
if (!barrier) {
|
||||
knownType = types->getKnownTypeTag();
|
||||
|
||||
// Null and undefined have no payload so they can't be specialized.
|
||||
@ -5253,6 +5254,11 @@ IonBuilder::jsop_getelem_dense()
|
||||
// constant.
|
||||
if (knownType == JSVAL_TYPE_UNDEFINED || knownType == JSVAL_TYPE_NULL)
|
||||
knownType = JSVAL_TYPE_UNKNOWN;
|
||||
|
||||
// Different architectures may want typed element reads which require
|
||||
// hole checks to be done as either value or typed reads.
|
||||
if (needsHoleCheck && !LIRGenerator::allowTypedElementHoleCheck())
|
||||
knownType = JSVAL_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
// Ensure id is an integer.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -624,7 +624,7 @@ class LInstruction
|
||||
|
||||
virtual bool isCall() const {
|
||||
return false;
|
||||
};
|
||||
}
|
||||
uint32_t id() const {
|
||||
return id_;
|
||||
}
|
||||
|
@ -125,8 +125,8 @@ class LinearScanAllocator : public LiveRangeAllocator<LinearScanVirtualRegister>
|
||||
void validateIntervals();
|
||||
void validateAllocations();
|
||||
#else
|
||||
inline void validateIntervals() { };
|
||||
inline void validateAllocations() { };
|
||||
inline void validateIntervals() { }
|
||||
inline void validateAllocations() { }
|
||||
#endif
|
||||
|
||||
#ifdef JS_NUNBOX32
|
||||
|
@ -1488,9 +1488,13 @@ LIRGenerator::visitLoadElement(MLoadElement *ins)
|
||||
return false;
|
||||
|
||||
default:
|
||||
JS_ASSERT(!ins->fallible());
|
||||
return define(new LLoadElementT(useRegister(ins->elements()),
|
||||
useRegisterOrConstant(ins->index())), ins);
|
||||
{
|
||||
LLoadElementT *lir = new LLoadElementT(useRegister(ins->elements()),
|
||||
useRegisterOrConstant(ins->index()));
|
||||
if (ins->fallible() && !assignSnapshot(lir))
|
||||
return false;
|
||||
return define(lir, ins);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
252
js/src/ion/MIR.h
252
js/src/ion/MIR.h
File diff suppressed because it is too large
Load Diff
@ -343,31 +343,31 @@ struct FunctionInfo<R (*)(JSContext *)> : public VMFunction {
|
||||
template <class R, class A1>
|
||||
struct FunctionInfo<R (*)(JSContext *, A1)> : public VMFunction {
|
||||
typedef R (*pf)(JSContext *, A1);
|
||||
FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_1);
|
||||
FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_1)
|
||||
};
|
||||
|
||||
template <class R, class A1, class A2>
|
||||
struct FunctionInfo<R (*)(JSContext *, A1, A2)> : public VMFunction {
|
||||
typedef R (*pf)(JSContext *, A1, A2);
|
||||
FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_2);
|
||||
FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_2)
|
||||
};
|
||||
|
||||
template <class R, class A1, class A2, class A3>
|
||||
struct FunctionInfo<R (*)(JSContext *, A1, A2, A3)> : public VMFunction {
|
||||
typedef R (*pf)(JSContext *, A1, A2, A3);
|
||||
FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_3);
|
||||
FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_3)
|
||||
};
|
||||
|
||||
template <class R, class A1, class A2, class A3, class A4>
|
||||
struct FunctionInfo<R (*)(JSContext *, A1, A2, A3, A4)> : public VMFunction {
|
||||
typedef R (*pf)(JSContext *, A1, A2, A3, A4);
|
||||
FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_4);
|
||||
FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_4)
|
||||
};
|
||||
|
||||
template <class R, class A1, class A2, class A3, class A4, class A5>
|
||||
struct FunctionInfo<R (*)(JSContext *, A1, A2, A3, A4, A5)> : public VMFunction {
|
||||
typedef R (*pf)(JSContext *, A1, A2, A3, A4, A5);
|
||||
FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_5);
|
||||
FUNCTION_INFO_STRUCT_BODY(FOR_EACH_ARGS_5)
|
||||
};
|
||||
|
||||
#undef FUNCTION_INFO_STRUCT_BODY
|
||||
|
@ -14,7 +14,7 @@ namespace ion {
|
||||
class LDivI : public LBinaryMath<1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(DivI);
|
||||
LIR_HEADER(DivI)
|
||||
|
||||
LDivI(const LAllocation &lhs, const LAllocation &rhs, const LDefinition &temp) {
|
||||
setOperand(0, lhs);
|
||||
@ -33,7 +33,7 @@ class LDivI : public LBinaryMath<1>
|
||||
class LModI : public LBinaryMath<1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(ModI);
|
||||
LIR_HEADER(ModI)
|
||||
|
||||
LModI(const LAllocation &lhs, const LAllocation &rhs) {
|
||||
setOperand(0, lhs);
|
||||
@ -50,7 +50,7 @@ class LModPowTwoI : public LInstructionHelper<1,1,0>
|
||||
const int32_t shift_;
|
||||
|
||||
public:
|
||||
LIR_HEADER(ModPowTwoI);
|
||||
LIR_HEADER(ModPowTwoI)
|
||||
|
||||
LModPowTwoI(const LAllocation &lhs, int32_t shift)
|
||||
: shift_(shift)
|
||||
@ -70,7 +70,7 @@ class LModPowTwoI : public LInstructionHelper<1,1,0>
|
||||
class LPowHalfD : public LInstructionHelper<1, 1, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(PowHalfD);
|
||||
LIR_HEADER(PowHalfD)
|
||||
LPowHalfD(const LAllocation &input, const LDefinition &temp) {
|
||||
setOperand(0, input);
|
||||
setTemp(0, temp);
|
||||
@ -91,7 +91,7 @@ class LPowHalfD : public LInstructionHelper<1, 1, 1>
|
||||
class LTableSwitch : public LInstructionHelper<0, 1, 2>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(TableSwitch);
|
||||
LIR_HEADER(TableSwitch)
|
||||
|
||||
LTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
|
||||
const LDefinition &jumpTablePointer, MTableSwitch *ins)
|
||||
@ -121,7 +121,7 @@ class LTableSwitch : public LInstructionHelper<0, 1, 2>
|
||||
class LTableSwitchV : public LInstructionHelper<0, BOX_PIECES, 3>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(TableSwitchV);
|
||||
LIR_HEADER(TableSwitchV)
|
||||
|
||||
LTableSwitchV(const LDefinition &inputCopy, const LDefinition &floatCopy,
|
||||
const LDefinition &jumpTablePointer, MTableSwitch *ins)
|
||||
@ -153,7 +153,7 @@ class LTableSwitchV : public LInstructionHelper<0, BOX_PIECES, 3>
|
||||
class LGuardShape : public LInstructionHelper<0, 1, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(GuardShape);
|
||||
LIR_HEADER(GuardShape)
|
||||
|
||||
LGuardShape(const LAllocation &in) {
|
||||
setOperand(0, in);
|
||||
@ -166,7 +166,7 @@ class LGuardShape : public LInstructionHelper<0, 1, 0>
|
||||
class LRecompileCheck : public LInstructionHelper<0, 0, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(RecompileCheck);
|
||||
LIR_HEADER(RecompileCheck)
|
||||
|
||||
const MRecompileCheck *mir() const {
|
||||
return mir_->toRecompileCheck();
|
||||
@ -176,13 +176,13 @@ class LRecompileCheck : public LInstructionHelper<0, 0, 0>
|
||||
class LInterruptCheck : public LInstructionHelper<0, 0, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(InterruptCheck);
|
||||
LIR_HEADER(InterruptCheck)
|
||||
};
|
||||
|
||||
class LMulI : public LBinaryMath<0, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(MulI);
|
||||
LIR_HEADER(MulI)
|
||||
|
||||
LMulI(const LAllocation &lhs, const LAllocation &rhs, const LAllocation &lhsCopy) {
|
||||
setOperand(0, lhs);
|
||||
|
@ -166,6 +166,11 @@ class LIRGeneratorShared : public MInstructionVisitor
|
||||
|
||||
public:
|
||||
bool visitConstant(MConstant *ins);
|
||||
|
||||
// Whether to generate typed reads for element accesses with hole checks.
|
||||
static bool allowTypedElementHoleCheck() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ion
|
||||
|
@ -19,7 +19,7 @@ class LBox : public LInstructionHelper<1, 1, 0>
|
||||
MIRType type_;
|
||||
|
||||
public:
|
||||
LIR_HEADER(Box);
|
||||
LIR_HEADER(Box)
|
||||
|
||||
LBox(MIRType type, const LAllocation &payload)
|
||||
: type_(type)
|
||||
@ -50,7 +50,7 @@ class LUnboxBase : public LInstructionHelper<1, 1, 0>
|
||||
|
||||
class LUnbox : public LUnboxBase {
|
||||
public:
|
||||
LIR_HEADER(Unbox);
|
||||
LIR_HEADER(Unbox)
|
||||
|
||||
LUnbox(const LAllocation &input)
|
||||
: LUnboxBase(input)
|
||||
@ -59,7 +59,7 @@ class LUnbox : public LUnboxBase {
|
||||
|
||||
class LUnboxDouble : public LUnboxBase {
|
||||
public:
|
||||
LIR_HEADER(UnboxDouble);
|
||||
LIR_HEADER(UnboxDouble)
|
||||
|
||||
LUnboxDouble(const LAllocation &input)
|
||||
: LUnboxBase(input)
|
||||
@ -72,7 +72,7 @@ class LDouble : public LInstructionHelper<1, 0, 0>
|
||||
double d_;
|
||||
|
||||
public:
|
||||
LIR_HEADER(Double);
|
||||
LIR_HEADER(Double)
|
||||
|
||||
LDouble(double d)
|
||||
: d_(d)
|
||||
|
@ -230,12 +230,17 @@ CodeGeneratorX86::visitLoadElementT(LLoadElementT *load)
|
||||
{
|
||||
Operand source = createArrayElementOperand(ToRegister(load->elements()), load->index());
|
||||
|
||||
if (load->mir()->needsHoleCheck()) {
|
||||
Assembler::Condition cond = masm.testMagic(Assembler::Equal, source);
|
||||
if (!bailoutIf(cond, load->snapshot()))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (load->mir()->type() == MIRType_Double)
|
||||
masm.loadInt32OrDouble(source, ToFloatRegister(load->output()));
|
||||
else
|
||||
masm.movl(masm.ToPayload(source), ToRegister(load->output()));
|
||||
|
||||
JS_ASSERT(!load->mir()->needsHoleCheck());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,10 @@ class LIRGeneratorX86 : public LIRGeneratorX86Shared
|
||||
bool visitReturn(MReturn *ret);
|
||||
bool visitStoreTypedArrayElement(MStoreTypedArrayElement *ins);
|
||||
bool lowerPhi(MPhi *phi);
|
||||
|
||||
static bool allowTypedElementHoleCheck() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
typedef LIRGeneratorX86 LIRGeneratorSpecific;
|
||||
|
@ -272,6 +272,11 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
||||
cmpl(tag, ImmTag(JSVAL_TAG_MAGIC));
|
||||
return cond;
|
||||
}
|
||||
Condition testMagic(Condition cond, const Operand &operand) {
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(ToType(operand), ImmTag(JSVAL_TAG_MAGIC));
|
||||
return cond;
|
||||
}
|
||||
Condition testPrimitive(Condition cond, const Register &tag) {
|
||||
JS_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, ImmTag(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET));
|
||||
|
@ -51,7 +51,7 @@ class TaggedProto
|
||||
template <>
|
||||
struct RootKind<TaggedProto>
|
||||
{
|
||||
static ThingRootKind rootKind() { return THING_ROOT_OBJECT; };
|
||||
static ThingRootKind rootKind() { return THING_ROOT_OBJECT; }
|
||||
};
|
||||
|
||||
template <> struct RootMethods<const TaggedProto>
|
||||
|
@ -49,8 +49,8 @@ class JS_FRIEND_API(Wrapper) : public DirectProxyHandler
|
||||
* is not safe to unwrap, operations requiring full access to the underlying
|
||||
* object (via UnwrapObjectChecked) will throw. Otherwise, they will succeed.
|
||||
*/
|
||||
void setSafeToUnwrap(bool safe) { mSafeToUnwrap = safe; };
|
||||
bool isSafeToUnwrap() { return mSafeToUnwrap; };
|
||||
void setSafeToUnwrap(bool safe) { mSafeToUnwrap = safe; }
|
||||
bool isSafeToUnwrap() { return mSafeToUnwrap; }
|
||||
|
||||
static JSObject *New(JSContext *cx, JSObject *obj, JSObject *proto,
|
||||
JSObject *parent, Wrapper *handler);
|
||||
|
@ -826,7 +826,7 @@ class FrameState
|
||||
#ifdef DEBUG
|
||||
void assertValidRegisterState() const;
|
||||
#else
|
||||
inline void assertValidRegisterState() const {};
|
||||
inline void assertValidRegisterState() const {}
|
||||
#endif
|
||||
|
||||
// Return an address, relative to the StackFrame, that represents where
|
||||
|
@ -24,7 +24,7 @@ namespace xpc {
|
||||
class ChromeObjectWrapper : public ChromeObjectWrapperBase
|
||||
{
|
||||
public:
|
||||
ChromeObjectWrapper() : ChromeObjectWrapperBase(0) {};
|
||||
ChromeObjectWrapper() : ChromeObjectWrapperBase(0) {}
|
||||
|
||||
/* Custom traps. */
|
||||
virtual bool getPropertyDescriptor(JSContext *cx, JSObject *wrapper,
|
||||
|
@ -49,6 +49,7 @@ FrameLayerBuilder::DisplayItemData::DisplayItemData(LayerManagerData* aParent, u
|
||||
, mLayerState(aLayerState)
|
||||
, mUsed(true)
|
||||
, mIsInvalid(false)
|
||||
, mIsVisible(true)
|
||||
{
|
||||
}
|
||||
|
||||
@ -66,6 +67,7 @@ FrameLayerBuilder::DisplayItemData::DisplayItemData(DisplayItemData &toCopy)
|
||||
mContainerLayerGeneration = toCopy.mContainerLayerGeneration;
|
||||
mLayerState = toCopy.mLayerState;
|
||||
mUsed = toCopy.mUsed;
|
||||
mIsVisible = toCopy.mIsVisible;
|
||||
}
|
||||
|
||||
void
|
||||
@ -1100,13 +1102,15 @@ FrameLayerBuilder::GetDisplayItemDataForManager(nsDisplayItem* aItem,
|
||||
}
|
||||
|
||||
bool
|
||||
FrameLayerBuilder::HasRetainedDataFor(nsIFrame* aFrame, uint32_t aDisplayItemKey)
|
||||
FrameLayerBuilder::HasVisibleRetainedDataFor(nsIFrame* aFrame, uint32_t aDisplayItemKey)
|
||||
{
|
||||
nsTArray<DisplayItemData*> *array =
|
||||
reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(LayerManagerDataProperty()));
|
||||
if (array) {
|
||||
for (uint32_t i = 0; i < array->Length(); i++) {
|
||||
if (array->ElementAt(i)->mDisplayItemKey == aDisplayItemKey) {
|
||||
DisplayItemData* data = array->ElementAt(i);
|
||||
if (data->mDisplayItemKey == aDisplayItemKey &&
|
||||
data->IsVisibleInLayer()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1115,7 +1119,7 @@ FrameLayerBuilder::HasRetainedDataFor(nsIFrame* aFrame, uint32_t aDisplayItemKey
|
||||
}
|
||||
|
||||
void
|
||||
FrameLayerBuilder::IterateRetainedDataFor(nsIFrame* aFrame, DisplayItemDataCallback aCallback)
|
||||
FrameLayerBuilder::IterateVisibleRetainedDataFor(nsIFrame* aFrame, DisplayItemDataCallback aCallback)
|
||||
{
|
||||
nsTArray<DisplayItemData*> *array =
|
||||
reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(LayerManagerDataProperty()));
|
||||
@ -1125,7 +1129,8 @@ FrameLayerBuilder::IterateRetainedDataFor(nsIFrame* aFrame, DisplayItemDataCallb
|
||||
|
||||
for (uint32_t i = 0; i < array->Length(); i++) {
|
||||
DisplayItemData* data = array->ElementAt(i);
|
||||
if (data->mDisplayItemKey != nsDisplayItem::TYPE_ZERO) {
|
||||
if (data->mDisplayItemKey != nsDisplayItem::TYPE_ZERO &&
|
||||
data->IsVisibleInLayer()) {
|
||||
aCallback(aFrame, data);
|
||||
}
|
||||
}
|
||||
@ -1841,7 +1846,7 @@ ContainerState::ThebesLayerData::Accumulate(ContainerState* aState,
|
||||
nsRegion opaqueClipped;
|
||||
nsRegionRectIterator iter(opaque);
|
||||
for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
|
||||
opaqueClipped.Or(opaqueClipped, aClip.ApproximateIntersect(*r));
|
||||
opaqueClipped.Or(opaqueClipped, aClip.ApproximateIntersectInner(*r));
|
||||
}
|
||||
|
||||
nsIntRegion opaquePixels = aState->ScaleRegionToInsidePixels(opaqueClipped, snap);
|
||||
@ -2348,6 +2353,7 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem,
|
||||
GetTranslationForThebesLayer(newThebesLayer));
|
||||
}
|
||||
}
|
||||
aItem->NotifyRenderingChanged();
|
||||
return;
|
||||
}
|
||||
if (!aNewLayer) {
|
||||
@ -2410,6 +2416,7 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem,
|
||||
#endif
|
||||
}
|
||||
if (!combined.IsEmpty()) {
|
||||
aItem->NotifyRenderingChanged();
|
||||
InvalidatePostTransformRegion(newThebesLayer,
|
||||
combined.ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel),
|
||||
GetTranslationForThebesLayer(newThebesLayer));
|
||||
@ -2454,7 +2461,8 @@ FrameLayerBuilder::AddThebesDisplayItem(ThebesLayer* aLayer,
|
||||
}
|
||||
}
|
||||
|
||||
AddLayerDisplayItem(aLayer, aItem, aClip, aLayerState, aTopLeft, tempManager, aGeometry);
|
||||
DisplayItemData* displayItemData =
|
||||
AddLayerDisplayItem(aLayer, aItem, aClip, aLayerState, aTopLeft, tempManager, aGeometry);
|
||||
|
||||
ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(aLayer);
|
||||
if (entry) {
|
||||
@ -2521,7 +2529,7 @@ FrameLayerBuilder::AddThebesDisplayItem(ThebesLayer* aLayer,
|
||||
}
|
||||
}
|
||||
ClippedDisplayItem* cdi =
|
||||
entry->mItems.AppendElement(ClippedDisplayItem(aItem, aClip,
|
||||
entry->mItems.AppendElement(ClippedDisplayItem(aItem, displayItemData, aClip,
|
||||
mContainerLayerGeneration));
|
||||
cdi->mInactiveLayerManager = tempManager;
|
||||
}
|
||||
@ -2596,7 +2604,7 @@ FrameLayerBuilder::ClippedDisplayItem::~ClippedDisplayItem()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FrameLayerBuilder::DisplayItemData*
|
||||
FrameLayerBuilder::AddLayerDisplayItem(Layer* aLayer,
|
||||
nsDisplayItem* aItem,
|
||||
const Clip& aClip,
|
||||
@ -2606,7 +2614,7 @@ FrameLayerBuilder::AddLayerDisplayItem(Layer* aLayer,
|
||||
nsAutoPtr<nsDisplayItemGeometry> aGeometry)
|
||||
{
|
||||
if (aLayer->Manager() != mRetainingManager)
|
||||
return;
|
||||
return nullptr;
|
||||
|
||||
DisplayItemData *data = StoreDataForFrame(aItem, aLayer, aLayerState);
|
||||
ThebesLayer *t = aLayer->AsThebesLayer();
|
||||
@ -2615,6 +2623,7 @@ FrameLayerBuilder::AddLayerDisplayItem(Layer* aLayer,
|
||||
data->mClip = aClip;
|
||||
}
|
||||
data->mInactiveManager = aManager;
|
||||
return data;
|
||||
}
|
||||
|
||||
nsIntPoint
|
||||
@ -3263,15 +3272,29 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
|
||||
int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
|
||||
|
||||
uint32_t i;
|
||||
// Update visible regions. We need perform visibility analysis again
|
||||
// because we may be asked to draw into part of a ThebesLayer that
|
||||
// isn't actually visible in the window (e.g., because a ThebesLayer
|
||||
// expanded its visible region to a rectangle internally), in which
|
||||
// case the mVisibleRect stored in the display item may be wrong.
|
||||
nsRegion visible = aRegionToDraw.ToAppUnits(appUnitsPerDevPixel);
|
||||
// Update visible rects in display items to reflect visibility
|
||||
// just considering items in this ThebesLayer. This is different from the
|
||||
// original visible rects, which describe which part of each item
|
||||
// is visible in the window. These can be larger than the original
|
||||
// visible rect, because we may be asked to draw into part of a
|
||||
// ThebesLayer that isn't actually visible in the window (e.g.,
|
||||
// because a ThebesLayer expanded its visible region to a rectangle
|
||||
// internally, or because we're caching prerendered content).
|
||||
// We also compute the intersection of those visible rects with
|
||||
// aRegionToDraw. These are the rectangles of each display item
|
||||
// that actually need to be drawn now.
|
||||
// Treat as visible everything this layer already contains or will
|
||||
// contain.
|
||||
nsIntRegion layerRegion;
|
||||
layerRegion.Or(aLayer->GetValidRegion(), aRegionToDraw);
|
||||
nsRegion visible = layerRegion.ToAppUnits(appUnitsPerDevPixel);
|
||||
visible.MoveBy(NSIntPixelsToAppUnits(offset.x, appUnitsPerDevPixel),
|
||||
NSIntPixelsToAppUnits(offset.y, appUnitsPerDevPixel));
|
||||
visible.ScaleInverseRoundOut(userData->mXScale, userData->mYScale);
|
||||
nsRegion toDraw = aRegionToDraw.ToAppUnits(appUnitsPerDevPixel);
|
||||
toDraw.MoveBy(NSIntPixelsToAppUnits(offset.x, appUnitsPerDevPixel),
|
||||
NSIntPixelsToAppUnits(offset.y, appUnitsPerDevPixel));
|
||||
toDraw.ScaleInverseRoundOut(userData->mXScale, userData->mYScale);
|
||||
|
||||
for (i = items.Length(); i > 0; --i) {
|
||||
ClippedDisplayItem* cdi = &items[i - 1];
|
||||
@ -3287,29 +3310,28 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
|
||||
(cdi->mClip.mRoundedClipRects.IsEmpty() &&
|
||||
cdi->mClip.mClipRect.Contains(visible.GetBounds()))) {
|
||||
cdi->mItem->RecomputeVisibility(builder, &visible);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do a little dance to account for the fact that we're clipping
|
||||
// to cdi->mClipRect
|
||||
nsRegion clipped;
|
||||
clipped.And(visible, cdi->mClip.mClipRect);
|
||||
nsRegion finalClipped = clipped;
|
||||
cdi->mItem->RecomputeVisibility(builder, &finalClipped);
|
||||
// If we have rounded clip rects, don't subtract from the visible
|
||||
// region since we aren't displaying everything inside the rect.
|
||||
if (cdi->mClip.mRoundedClipRects.IsEmpty()) {
|
||||
nsRegion removed;
|
||||
removed.Sub(clipped, finalClipped);
|
||||
nsRegion newVisible;
|
||||
newVisible.Sub(visible, removed);
|
||||
// Don't let the visible region get too complex.
|
||||
if (newVisible.GetNumRects() <= 15) {
|
||||
visible = newVisible;
|
||||
} else {
|
||||
// Do a little dance to account for the fact that we're clipping
|
||||
// to cdi->mClipRect
|
||||
nsRegion clipped;
|
||||
clipped.And(visible, cdi->mClip.mClipRect);
|
||||
nsRegion finalClipped = clipped;
|
||||
cdi->mItem->RecomputeVisibility(builder, &finalClipped);
|
||||
// If we have rounded clip rects, don't subtract from the visible
|
||||
// region since we aren't displaying everything inside the rect.
|
||||
if (cdi->mClip.mRoundedClipRects.IsEmpty()) {
|
||||
nsRegion removed;
|
||||
removed.Sub(clipped, finalClipped);
|
||||
nsRegion newVisible;
|
||||
newVisible.Sub(visible, removed);
|
||||
// Don't let the visible region get too complex.
|
||||
if (newVisible.GetNumRects() <= 15) {
|
||||
visible = newVisible;
|
||||
}
|
||||
}
|
||||
if (!cdi->mClip.IsRectClippedByRoundedCorner(cdi->mItem->GetVisibleRect())) {
|
||||
cdi->mClip.RemoveRoundedCorners();
|
||||
}
|
||||
}
|
||||
if (!cdi->mClip.IsRectClippedByRoundedCorner(cdi->mItem->GetVisibleRect())) {
|
||||
cdi->mClip.RemoveRoundedCorners();
|
||||
}
|
||||
}
|
||||
|
||||
@ -3322,8 +3344,13 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
|
||||
for (i = 0; i < items.Length(); ++i) {
|
||||
ClippedDisplayItem* cdi = &items[i];
|
||||
|
||||
if (cdi->mItem->GetVisibleRect().IsEmpty())
|
||||
if (cdi->mData) {
|
||||
cdi->mData->SetIsVisibleInLayer(!cdi->mItem->GetVisibleRect().IsEmpty());
|
||||
}
|
||||
|
||||
if (!toDraw.Intersects(cdi->mItem->GetVisibleRect())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the new desired clip state is different from the current state,
|
||||
// update the clip.
|
||||
@ -3501,7 +3528,7 @@ FrameLayerBuilder::Clip::AddRoundedRectPathTo(gfxContext* aContext,
|
||||
}
|
||||
|
||||
nsRect
|
||||
FrameLayerBuilder::Clip::ApproximateIntersect(const nsRect& aRect) const
|
||||
FrameLayerBuilder::Clip::ApproximateIntersectInner(const nsRect& aRect) const
|
||||
{
|
||||
nsRect r = aRect;
|
||||
if (mHaveClipRect) {
|
||||
|
@ -96,6 +96,7 @@ public:
|
||||
typedef layers::ThebesLayer ThebesLayer;
|
||||
typedef layers::ImageLayer ImageLayer;
|
||||
typedef layers::LayerManager LayerManager;
|
||||
class DisplayItemData;
|
||||
|
||||
FrameLayerBuilder() :
|
||||
mRetainingManager(nullptr),
|
||||
@ -263,13 +264,13 @@ public:
|
||||
* then this is the temporary layer manager to draw with.
|
||||
*/
|
||||
struct Clip;
|
||||
void AddLayerDisplayItem(Layer* aLayer,
|
||||
nsDisplayItem* aItem,
|
||||
const Clip& aClip,
|
||||
LayerState aLayerState,
|
||||
const nsPoint& aTopLeft,
|
||||
LayerManager* aManager,
|
||||
nsAutoPtr<nsDisplayItemGeometry> aGeometry);
|
||||
DisplayItemData* AddLayerDisplayItem(Layer* aLayer,
|
||||
nsDisplayItem* aItem,
|
||||
const Clip& aClip,
|
||||
LayerState aLayerState,
|
||||
const nsPoint& aTopLeft,
|
||||
LayerManager* aManager,
|
||||
nsAutoPtr<nsDisplayItemGeometry> aGeometry);
|
||||
|
||||
/**
|
||||
* Record aItem as a display item that is rendered by the ThebesLayer
|
||||
@ -314,15 +315,14 @@ public:
|
||||
LayerManager* GetRetainingLayerManager() { return mRetainingManager; }
|
||||
|
||||
/**
|
||||
* Returns true if the given display item was rendered during the previous
|
||||
* paint. Returns false otherwise.
|
||||
* Returns true if the given display item was visible in its layer during
|
||||
* the previous paint. Returns false otherwise.
|
||||
*/
|
||||
static bool HasRetainedDataFor(nsIFrame* aFrame, uint32_t aDisplayItemKey);
|
||||
static bool HasVisibleRetainedDataFor(nsIFrame* aFrame, uint32_t aDisplayItemKey);
|
||||
|
||||
class DisplayItemData;
|
||||
typedef void (*DisplayItemDataCallback)(nsIFrame *aFrame, DisplayItemData* aItem);
|
||||
|
||||
static void IterateRetainedDataFor(nsIFrame* aFrame, DisplayItemDataCallback aCallback);
|
||||
static void IterateVisibleRetainedDataFor(nsIFrame* aFrame, DisplayItemDataCallback aCallback);
|
||||
|
||||
/**
|
||||
* Save transform that was in aLayer when we last painted, and the position
|
||||
@ -417,7 +417,7 @@ public:
|
||||
// Return a rectangle contained in the intersection of aRect with this
|
||||
// clip region. Tries to return the largest possible rectangle, but may
|
||||
// not succeed.
|
||||
nsRect ApproximateIntersect(const nsRect& aRect) const;
|
||||
nsRect ApproximateIntersectInner(const nsRect& aRect) const;
|
||||
|
||||
// Returns false if aRect is definitely not clipped by a rounded corner in
|
||||
// this clip. Returns true if aRect is clipped by a rounded corner in this
|
||||
@ -477,6 +477,9 @@ public:
|
||||
uint32_t GetDisplayItemKey() { return mDisplayItemKey; }
|
||||
Layer* GetLayer() { return mLayer; }
|
||||
void Invalidate() { mIsInvalid = true; }
|
||||
bool IsVisibleInLayer() { return mIsVisible; }
|
||||
void SetIsVisibleInLayer(bool aIsVisible) { mIsVisible = aIsVisible; }
|
||||
|
||||
protected:
|
||||
|
||||
DisplayItemData(LayerManagerData* aParent, uint32_t aKey, Layer* aLayer, LayerState aLayerState, uint32_t aGeneration);
|
||||
@ -525,7 +528,15 @@ public:
|
||||
* paint) has been updated in the current paint.
|
||||
*/
|
||||
bool mUsed;
|
||||
/**
|
||||
* True if the entire display item needs to be invalidated.
|
||||
*/
|
||||
bool mIsInvalid;
|
||||
/**
|
||||
* True if the display item is visible in its layer, otherwise
|
||||
* it's completely covered by opaque content in its ThebesLayer.
|
||||
*/
|
||||
bool mIsVisible;
|
||||
};
|
||||
|
||||
protected:
|
||||
@ -592,14 +603,17 @@ protected:
|
||||
* mItem always has an underlying frame.
|
||||
*/
|
||||
struct ClippedDisplayItem {
|
||||
ClippedDisplayItem(nsDisplayItem* aItem, const Clip& aClip, uint32_t aGeneration)
|
||||
: mItem(aItem), mClip(aClip), mContainerLayerGeneration(aGeneration)
|
||||
ClippedDisplayItem(nsDisplayItem* aItem, DisplayItemData* aData,
|
||||
const Clip& aClip, uint32_t aGeneration)
|
||||
: mItem(aItem), mData(aData), mClip(aClip),
|
||||
mContainerLayerGeneration(aGeneration)
|
||||
{
|
||||
}
|
||||
|
||||
~ClippedDisplayItem();
|
||||
|
||||
nsDisplayItem* mItem;
|
||||
DisplayItemData* mData;
|
||||
|
||||
/**
|
||||
* If the display item is being rendered as an inactive
|
||||
|
@ -109,7 +109,8 @@ CollectRestyles(nsISupports* aElement,
|
||||
inline void
|
||||
RestyleTracker::ProcessOneRestyle(Element* aElement,
|
||||
nsRestyleHint aRestyleHint,
|
||||
nsChangeHint aChangeHint)
|
||||
nsChangeHint aChangeHint,
|
||||
OverflowChangedTracker& aTracker)
|
||||
{
|
||||
NS_PRECONDITION((aRestyleHint & eRestyle_LaterSiblings) == 0,
|
||||
"Someone should have handled this before calling us");
|
||||
@ -121,14 +122,15 @@ RestyleTracker::ProcessOneRestyle(Element* aElement,
|
||||
if (aRestyleHint & (eRestyle_Self | eRestyle_Subtree)) {
|
||||
mFrameConstructor->RestyleElement(aElement, primaryFrame, aChangeHint,
|
||||
*this,
|
||||
(aRestyleHint & eRestyle_Subtree) != 0);
|
||||
(aRestyleHint & eRestyle_Subtree) != 0,
|
||||
aTracker);
|
||||
} else if (aChangeHint &&
|
||||
(primaryFrame ||
|
||||
(aChangeHint & nsChangeHint_ReconstructFrame))) {
|
||||
// Don't need to recompute style; just apply the hint
|
||||
nsStyleChangeList changeList;
|
||||
changeList.AppendChange(primaryFrame, aElement, aChangeHint);
|
||||
mFrameConstructor->ProcessRestyledFrames(changeList);
|
||||
mFrameConstructor->ProcessRestyledFrames(changeList, aTracker);
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,6 +144,8 @@ RestyleTracker::DoProcessRestyles()
|
||||
|
||||
mFrameConstructor->mInStyleRefresh = true;
|
||||
|
||||
OverflowChangedTracker tracker;
|
||||
|
||||
// loop so that we process any restyle events generated by processing
|
||||
while (mPendingRestyles.Count()) {
|
||||
if (mHaveLaterSiblingRestyles) {
|
||||
@ -206,7 +210,7 @@ RestyleTracker::DoProcessRestyles()
|
||||
continue;
|
||||
}
|
||||
|
||||
ProcessOneRestyle(element, data.mRestyleHint, data.mChangeHint);
|
||||
ProcessOneRestyle(element, data.mRestyleHint, data.mChangeHint, tracker);
|
||||
}
|
||||
|
||||
if (mHaveLaterSiblingRestyles) {
|
||||
@ -235,11 +239,14 @@ RestyleTracker::DoProcessRestyles()
|
||||
++currentRestyle) {
|
||||
ProcessOneRestyle(currentRestyle->mElement,
|
||||
currentRestyle->mRestyleHint,
|
||||
currentRestyle->mChangeHint);
|
||||
currentRestyle->mChangeHint,
|
||||
tracker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tracker.Flush();
|
||||
|
||||
// Set mInStyleRefresh to false now, since the EndUpdate call might
|
||||
// add more restyles.
|
||||
mFrameConstructor->mInStyleRefresh = false;
|
||||
|
@ -14,12 +14,136 @@
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsTPriorityQueue.h"
|
||||
|
||||
class nsCSSFrameConstructor;
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
|
||||
/**
|
||||
* Helper class that collects a list of frames that need
|
||||
* UpdateOverflow() called on them, and coalesces them
|
||||
* to avoid walking up the same ancestor tree multiple times.
|
||||
*/
|
||||
class OverflowChangedTracker
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Add a frame that has had a style change, and needs its
|
||||
* overflow updated.
|
||||
*
|
||||
* If there are pre-transform overflow areas stored for this
|
||||
* frame, then we will call FinishAndStoreOverflow with those
|
||||
* areas instead of UpdateOverflow().
|
||||
*
|
||||
* If the overflow area changes, then UpdateOverflow will also
|
||||
* be called on the parent.
|
||||
*/
|
||||
void AddFrame(nsIFrame* aFrame) {
|
||||
mEntryList.Push(Entry(aFrame, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the overflow of all added frames, and clear the entry list.
|
||||
*
|
||||
* Start from those deepest in the frame tree and works upwards. This stops
|
||||
* us from processing the same frame twice.
|
||||
*/
|
||||
void Flush() {
|
||||
while (!mEntryList.IsEmpty()) {
|
||||
Entry entry = mEntryList.Pop();
|
||||
|
||||
// Pop off any duplicate entries and copy back mInitial
|
||||
// if any have it set.
|
||||
while (!mEntryList.IsEmpty() &&
|
||||
mEntryList.Top().mFrame == entry.mFrame) {
|
||||
Entry next = mEntryList.Pop();
|
||||
|
||||
if (next.mInitial) {
|
||||
entry.mInitial = true;
|
||||
}
|
||||
}
|
||||
nsIFrame *frame = entry.mFrame;
|
||||
|
||||
bool updateParent = false;
|
||||
if (entry.mInitial) {
|
||||
nsOverflowAreas* pre = static_cast<nsOverflowAreas*>
|
||||
(frame->Properties().Get(frame->PreTransformOverflowAreasProperty()));
|
||||
if (pre) {
|
||||
// FinishAndStoreOverflow will change the overflow areas passed in,
|
||||
// so make a copy.
|
||||
nsOverflowAreas overflowAreas = *pre;
|
||||
frame->FinishAndStoreOverflow(overflowAreas, frame->GetSize());
|
||||
// We can't tell if the overflow changed, so update the parent regardless
|
||||
updateParent = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If the overflow changed, then we want to also update the parent's
|
||||
// overflow. We always update the parent for initial frames.
|
||||
if (!updateParent) {
|
||||
updateParent = frame->UpdateOverflow() || entry.mInitial;
|
||||
}
|
||||
if (updateParent) {
|
||||
nsIFrame *parent = frame->GetParent();
|
||||
if (parent) {
|
||||
mEntryList.Push(Entry(parent, entry.mDepth - 1, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct Entry
|
||||
{
|
||||
Entry(nsIFrame* aFrame, bool aInitial)
|
||||
: mFrame(aFrame)
|
||||
, mDepth(aFrame->GetDepthInFrameTree())
|
||||
, mInitial(aInitial)
|
||||
{}
|
||||
|
||||
Entry(nsIFrame* aFrame, uint32_t aDepth, bool aInitial)
|
||||
: mFrame(aFrame)
|
||||
, mDepth(aDepth)
|
||||
, mInitial(aInitial)
|
||||
{}
|
||||
|
||||
bool operator==(const Entry& aOther) const
|
||||
{
|
||||
return mFrame == aOther.mFrame;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort by the depth in the frame tree, and then
|
||||
* the frame pointer.
|
||||
*/
|
||||
bool operator<(const Entry& aOther) const
|
||||
{
|
||||
if (mDepth != aOther.mDepth) {
|
||||
// nsTPriorityQueue implements a min-heap and we
|
||||
// want the highest depth first, so reverse this check.
|
||||
return mDepth > aOther.mDepth;
|
||||
}
|
||||
|
||||
return mFrame < aOther.mFrame;
|
||||
}
|
||||
|
||||
nsIFrame* mFrame;
|
||||
/* Depth in the frame tree */
|
||||
uint32_t mDepth;
|
||||
/**
|
||||
* True if the frame had the actual style change, and we
|
||||
* want to check for pre-transform overflow areas.
|
||||
*/
|
||||
bool mInitial;
|
||||
};
|
||||
|
||||
/* A list of frames to process, sorted by their depth in the frame tree */
|
||||
nsTPriorityQueue<Entry> mEntryList;
|
||||
};
|
||||
|
||||
class RestyleTracker {
|
||||
public:
|
||||
typedef mozilla::dom::Element Element;
|
||||
@ -114,7 +238,8 @@ private:
|
||||
*/
|
||||
inline void ProcessOneRestyle(Element* aElement,
|
||||
nsRestyleHint aRestyleHint,
|
||||
nsChangeHint aChangeHint);
|
||||
nsChangeHint aChangeHint,
|
||||
OverflowChangedTracker& aTracker);
|
||||
|
||||
/**
|
||||
* The guts of our restyle processing.
|
||||
|
@ -7764,7 +7764,6 @@ DoApplyRenderingChangeToTree(nsIFrame* aFrame,
|
||||
}
|
||||
if (aChange & nsChangeHint_UpdateTransformLayer) {
|
||||
aFrame->MarkLayersActive(nsChangeHint_UpdateTransformLayer);
|
||||
aFrame->AddStateBits(NS_FRAME_TRANSFORM_CHANGED);
|
||||
// If we're not already going to do an invalidating paint, see
|
||||
// if we can get away with only updating the transform on a
|
||||
// layer for this frame, and not scheduling an invalidating
|
||||
@ -8057,7 +8056,8 @@ NeedToReframeForAddingOrRemovingTransform(nsIFrame* aFrame)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
|
||||
nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList,
|
||||
OverflowChangedTracker& aTracker)
|
||||
{
|
||||
NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
|
||||
"Someone forgot a script blocker");
|
||||
@ -8209,30 +8209,10 @@ nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
|
||||
if (!(frame->GetStateBits() &
|
||||
(NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) {
|
||||
while (frame) {
|
||||
nsOverflowAreas* pre = static_cast<nsOverflowAreas*>
|
||||
(frame->Properties().Get(frame->PreTransformOverflowAreasProperty()));
|
||||
if (pre) {
|
||||
// FinishAndStoreOverflow will change the overflow areas passed in,
|
||||
// so make a copy.
|
||||
nsOverflowAreas overflowAreas = *pre;
|
||||
frame->FinishAndStoreOverflow(overflowAreas, frame->GetSize());
|
||||
} else {
|
||||
frame->UpdateOverflow();
|
||||
}
|
||||
aTracker.AddFrame(frame);
|
||||
|
||||
nsIFrame* next =
|
||||
frame =
|
||||
nsLayoutUtils::GetNextContinuationOrSpecialSibling(frame);
|
||||
// Update the ancestors' overflow after we have updated the overflow
|
||||
// for all the continuations with the same parent.
|
||||
if (!next || frame->GetParent() != next->GetParent()) {
|
||||
for (nsIFrame* ancestor = frame->GetParent(); ancestor;
|
||||
ancestor = ancestor->GetParent()) {
|
||||
if (!ancestor->UpdateOverflow()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
frame = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8277,7 +8257,8 @@ nsCSSFrameConstructor::RestyleElement(Element *aElement,
|
||||
nsIFrame *aPrimaryFrame,
|
||||
nsChangeHint aMinHint,
|
||||
RestyleTracker& aRestyleTracker,
|
||||
bool aRestyleDescendants)
|
||||
bool aRestyleDescendants,
|
||||
OverflowChangedTracker& aTracker)
|
||||
{
|
||||
NS_ASSERTION(aPrimaryFrame == aElement->GetPrimaryFrame(),
|
||||
"frame/content mismatch");
|
||||
@ -8314,7 +8295,7 @@ nsCSSFrameConstructor::RestyleElement(Element *aElement,
|
||||
nsStyleChangeList changeList;
|
||||
ComputeStyleChangeFor(aPrimaryFrame, &changeList, aMinHint,
|
||||
aRestyleTracker, aRestyleDescendants);
|
||||
ProcessRestyledFrames(changeList);
|
||||
ProcessRestyledFrames(changeList, aTracker);
|
||||
} else {
|
||||
// no frames, reconstruct for content
|
||||
MaybeRecreateFramesForElement(aElement);
|
||||
@ -12069,7 +12050,9 @@ nsCSSFrameConstructor::DoRebuildAllStyleData(RestyleTracker& aRestyleTracker,
|
||||
&changeList, aExtraHint,
|
||||
aRestyleTracker, true);
|
||||
// Process the required changes
|
||||
ProcessRestyledFrames(changeList);
|
||||
OverflowChangedTracker tracker;
|
||||
ProcessRestyledFrames(changeList, tracker);
|
||||
tracker.Flush();
|
||||
|
||||
// Tell the style set it's safe to destroy the old rule tree. We
|
||||
// must do this after the ProcessRestyledFrames call in case the
|
||||
|
@ -53,6 +53,7 @@ class nsCSSFrameConstructor : public nsFrameManager
|
||||
public:
|
||||
typedef mozilla::dom::Element Element;
|
||||
typedef mozilla::css::RestyleTracker RestyleTracker;
|
||||
typedef mozilla::css::OverflowChangedTracker OverflowChangedTracker;
|
||||
|
||||
nsCSSFrameConstructor(nsIDocument *aDocument, nsIPresShell* aPresShell);
|
||||
~nsCSSFrameConstructor(void) {
|
||||
@ -236,7 +237,8 @@ public:
|
||||
// This function does not call ProcessAttachedQueue() on the binding manager.
|
||||
// If the caller wants that to happen synchronously, it needs to handle that
|
||||
// itself.
|
||||
nsresult ProcessRestyledFrames(nsStyleChangeList& aRestyleArray);
|
||||
nsresult ProcessRestyledFrames(nsStyleChangeList& aRestyleArray,
|
||||
OverflowChangedTracker& aTracker);
|
||||
|
||||
private:
|
||||
|
||||
@ -390,7 +392,8 @@ private:
|
||||
nsIFrame* aPrimaryFrame,
|
||||
nsChangeHint aMinHint,
|
||||
RestyleTracker& aRestyleTracker,
|
||||
bool aRestyleDescendants);
|
||||
bool aRestyleDescendants,
|
||||
OverflowChangedTracker& aTracker);
|
||||
|
||||
nsresult InitAndRestoreFrame (const nsFrameConstructorState& aState,
|
||||
nsIContent* aContent,
|
||||
|
@ -2845,7 +2845,8 @@ nsCSSRendering::ComputeBackgroundPositioningArea(nsPresContext* aPresContext,
|
||||
}
|
||||
|
||||
nsIFrame* attachedToFrame = aForFrame;
|
||||
if (NS_STYLE_BG_ATTACHMENT_FIXED == aLayer.mAttachment) {
|
||||
if (NS_STYLE_BG_ATTACHMENT_FIXED == aLayer.mAttachment &&
|
||||
!aLayer.mImage.IsEmpty()) {
|
||||
// If it's a fixed background attachment, then the image is placed
|
||||
// relative to the viewport, which is the area of the root frame
|
||||
// in a screen context or the page content frame in a print context.
|
||||
@ -4689,26 +4690,19 @@ nsImageRenderer::Draw(nsPresContext* aPresContext,
|
||||
bool
|
||||
nsImageRenderer::IsRasterImage()
|
||||
{
|
||||
if (mType != eStyleImageType_Image)
|
||||
if (mType != eStyleImageType_Image || !mImageContainer)
|
||||
return false;
|
||||
nsCOMPtr<imgIContainer> img;
|
||||
if (NS_FAILED(mImage->GetImageData()->GetImage(getter_AddRefs(img))))
|
||||
return false;
|
||||
return img->GetType() == imgIContainer::TYPE_RASTER;
|
||||
return mImageContainer->GetType() == imgIContainer::TYPE_RASTER;
|
||||
}
|
||||
|
||||
already_AddRefed<mozilla::layers::ImageContainer>
|
||||
nsImageRenderer::GetContainer(LayerManager* aManager)
|
||||
{
|
||||
if (mType != eStyleImageType_Image)
|
||||
return nullptr;
|
||||
nsCOMPtr<imgIContainer> img;
|
||||
nsresult rv = mImage->GetImageData()->GetImage(getter_AddRefs(img));
|
||||
if (NS_FAILED(rv))
|
||||
if (mType != eStyleImageType_Image || !mImageContainer)
|
||||
return nullptr;
|
||||
|
||||
nsRefPtr<ImageContainer> container;
|
||||
rv = img->GetImageContainer(aManager, getter_AddRefs(container));
|
||||
nsresult rv = mImageContainer->GetImageContainer(aManager, getter_AddRefs(container));
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
return container.forget();
|
||||
}
|
||||
|
@ -855,7 +855,17 @@ public:
|
||||
aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called when the area rendered by this display item has changed (been
|
||||
* invalidated or changed geometry) since the last paint. This includes
|
||||
* when the display item was not rendered at all in the last paint.
|
||||
* It does NOT get called when a display item was being rendered and no
|
||||
* longer is, because generally that means there is no display item to
|
||||
* call this method on.
|
||||
*/
|
||||
virtual void NotifyRenderingChanged() {}
|
||||
|
||||
/**
|
||||
* @param aSnap set to true if the edges of the rectangles of the opaque
|
||||
* region would be snapped to device pixels when drawing
|
||||
|
@ -2725,7 +2725,9 @@ PresShell::RecreateFramesFor(nsIContent* aContent)
|
||||
|
||||
// Mark ourselves as not safe to flush while we're doing frame construction.
|
||||
++mChangeNestCount;
|
||||
nsresult rv = mFrameConstructor->ProcessRestyledFrames(changeList);
|
||||
css::OverflowChangedTracker tracker;
|
||||
nsresult rv = mFrameConstructor->ProcessRestyledFrames(changeList, tracker);
|
||||
tracker.Flush();
|
||||
--mChangeNestCount;
|
||||
|
||||
return rv;
|
||||
@ -7840,7 +7842,9 @@ PresShell::Observe(nsISupports* aSubject,
|
||||
{
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
++mChangeNestCount;
|
||||
mFrameConstructor->ProcessRestyledFrames(changeList);
|
||||
css::OverflowChangedTracker tracker;
|
||||
mFrameConstructor->ProcessRestyledFrames(changeList, tracker);
|
||||
tracker.Flush();
|
||||
--mChangeNestCount;
|
||||
}
|
||||
}
|
||||
|
@ -25,9 +25,7 @@
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsIViewManager.h"
|
||||
#include "sampler.h"
|
||||
|
||||
using mozilla::TimeStamp;
|
||||
using mozilla::TimeDuration;
|
||||
#include "nsNPAPIPluginInstance.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
@ -310,6 +308,11 @@ nsRefreshDriver::Notify(nsITimer *aTimer)
|
||||
NS_PRECONDITION(mPresContext, "Why are we notified after disconnection?");
|
||||
NS_PRECONDITION(!nsContentUtils::GetCurrentJSContext(),
|
||||
"Shouldn't have a JSContext on the stack");
|
||||
if (nsNPAPIPluginInstance::InPluginCall()) {
|
||||
NS_ERROR("Refresh driver should not run during plugin call!");
|
||||
// Try to survive this by just ignoring the refresh tick.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mTestControllingRefreshes && aTimer) {
|
||||
// Ignore real refreshes from our timer (but honor the others).
|
||||
|
@ -239,7 +239,6 @@ nsDisplayCanvasBackground::Paint(nsDisplayListBuilder* aBuilder,
|
||||
BlitSurface(dest, destRect, surf);
|
||||
|
||||
GetUnderlyingFrame()->Properties().Set(nsIFrame::CachedBackgroundImage(), surf.forget().get());
|
||||
GetUnderlyingFrame()->AddStateBits(NS_FRAME_HAS_CACHED_BACKGROUND);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,6 +181,10 @@ public:
|
||||
mBackgroundStyle->mLayers[mLayer].mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED &&
|
||||
!mBackgroundStyle->mLayers[mLayer].mImage.IsEmpty();
|
||||
}
|
||||
virtual void NotifyRenderingChanged() MOZ_OVERRIDE
|
||||
{
|
||||
mFrame->Properties().Delete(nsIFrame::CachedBackgroundImage());
|
||||
}
|
||||
|
||||
virtual void Paint(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext* aCtx) MOZ_OVERRIDE;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user