659 },
660
661 _coerceRemoteArrayOfDOMNodes: function(objectId, callback)
662 {
663 var length, nodes, received = 0, lastError = null, domTreeManager = this;
664
665 function nodeRequested(index, error, nodeId)
666 {
667 if (error)
668 lastError = error;
669 else
670 nodes[index] = domTreeManager._idToDOMNode[nodeId];
671 if (++received === length)
672 callback(lastError, nodes);
673 }
674
675 WebInspector.runtimeManager.getPropertiesForRemoteObject(objectId, function(error, properties) {
676 if (error) {
677 callback(error);
678 return;
679 }
680
681 var lengthProperty = properties.get("length");
682 if (!lengthProperty || lengthProperty.value.type !== "number") {
683 callback(null);
684 return;
685 }
686
687 length = lengthProperty.value.value;
688 if (!length) {
689 callback(null, []);
690 return;
691 }
692
693 nodes = new Array(length);
694 for (var i = 0; i < length; ++i) {
695 var nodeProperty = properties.get(String(i));
696 console.assert(nodeProperty.value.type === "object");
697 DOMAgent.requestNode(nodeProperty.value.objectId, nodeRequested.bind(null, i));
698 }
699 });
700 },
701
702 getNodeContentFlowInfo: function(domNode, resultReadyCallback)
703 {
704 DOMAgent.resolveNode(domNode.id, domNodeResolved.bind(this));
705
706 function domNodeResolved(error, remoteObject)
707 {
708 if (error) {
709 resultReadyCallback(error);
710 return;
711 }
712 // Serialize "backendFunction" and execute it in the context of the page
713 // passing the DOMNode as the "this" reference.
714 var evalParameters = {
715 objectId: remoteObject.objectId,
716 functionDeclaration: backendFunction.toString(),
717 doNotPauseOnExceptionsAndMuteConsole: true,
718 returnByValue: false,
719 generatePreview: false
720 };
721 RuntimeAgent.callFunctionOn.invoke(evalParameters, regionNodesAvailable.bind(this));
722 }
723
724 function regionNodesAvailable(error, remoteObject, wasThrown)
725 {
726 if (error) {
727 resultReadyCallback(error);
728 return;
729 }
730
731 if (wasThrown) {
732 // We should never get here, but having the error is useful for debugging.
733 console.error("Error while executing backend function:", JSON.stringify(remoteObject));
734 resultReadyCallback(null);
735 return;
736 }
737
738 // The backend function can never return null.
739 console.assert(remoteObject.type === "object");
740 console.assert(remoteObject.objectId);
741 WebInspector.runtimeManager.getPropertiesForRemoteObject(remoteObject.objectId, remoteObjectPropertiesAvailable.bind(this));
742 }
743
744 function remoteObjectPropertiesAvailable(error, properties) {
745 if (error) {
746 resultReadyCallback(error);
747 return;
748 }
749
750 var result = {
751 regionFlow: null,
752 contentFlow: null,
753 regions: null
754 };
755
756 var regionFlowNameProperty = properties.get("regionFlowName");
757 if (regionFlowNameProperty && regionFlowNameProperty.value && regionFlowNameProperty.value.value) {
758 console.assert(regionFlowNameProperty.value.type === "string");
759 var regionFlowKey = WebInspector.DOMTreeManager._flowPayloadHashKey({documentNodeId: domNode.ownerDocument.id, name: regionFlowNameProperty.value.value});
760 result.regionFlow = this._flows.get(regionFlowKey);
761 }
762
763 var contentFlowNameProperty = properties.get("contentFlowName");
764 if (contentFlowNameProperty && contentFlowNameProperty.value && contentFlowNameProperty.value.value) {
765 console.assert(contentFlowNameProperty.value.type === "string");
766 var contentFlowKey = WebInspector.DOMTreeManager._flowPayloadHashKey({documentNodeId: domNode.ownerDocument.id, name: contentFlowNameProperty.value.value});
767 result.contentFlow = this._flows.get(contentFlowKey);
768 }
769
770 var regionsProperty = properties.get("regions");
771 if (!regionsProperty || !regionsProperty.value.objectId) {
772 // The list of regions is null.
773 resultReadyCallback(null, result);
774 return;
775 }
776
777 console.assert(regionsProperty.value.type === "object");
778 console.assert(regionsProperty.value.subtype === "array");
779 this._coerceRemoteArrayOfDOMNodes(regionsProperty.value.objectId, function(error, nodes) {
780 result.regions = nodes;
781 resultReadyCallback(error, result);
782 });
783 }
784
785 // Note that "backendFunction" is serialized and executed in the context of the page.
786 function backendFunction()
787 {
788 function getComputedProperty(node, propertyName)
789 {
790 if (!node.ownerDocument || !node.ownerDocument.defaultView)
791 return null;
792 var computedStyle = node.ownerDocument.defaultView.getComputedStyle(node);
793 return computedStyle ? computedStyle[propertyName] : null;
794 }
795
796 function getContentFlowName(node)
797 {
798 for (; node; node = node.parentNode) {
799 var flowName = getComputedProperty(node, "webkitFlowInto");
800 if (flowName && flowName !== "none")
801 return flowName;
802 }
803 return null;
804 }
805
806 var node = this;
807
808 // Even detached nodes have an ownerDocument.
809 console.assert(node.ownerDocument);
810
811 var result = {
812 regionFlowName: getComputedProperty(node, "webkitFlowFrom"),
813 contentFlowName: getContentFlowName(node),
814 regions: null
815 };
816
817 if (result.contentFlowName) {
818 var flowThread = node.ownerDocument.webkitGetNamedFlows().namedItem(result.contentFlowName);
819 if (flowThread)
820 result.regions = flowThread.getRegionsByContent(node);
821 }
822
823 return result;
824 }