[154899] DirtyRegionProcessor#contains is called a lot
diff --git a/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/reconcile/DirtyRegionProcessor.java b/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/reconcile/DirtyRegionProcessor.java
index f9166fd..0149033 100644
--- a/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/reconcile/DirtyRegionProcessor.java
+++ b/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/reconcile/DirtyRegionProcessor.java
@@ -211,18 +211,20 @@
 	 * @param resource
 	 */
 	private synchronized void addRequest(DirtyRegion newDirtyRegion) {
+		// NOTE: This method is called a lot so make sure it's fast
 		List dirtyRegionQueue = getDirtyRegionQueue();
-		// if we already have a request which contains the new request,
-		// discare the new request
-		int size = dirtyRegionQueue.size();
-		for (int i = 0; i < size; i++) {
-			if (contains((DirtyRegion) dirtyRegionQueue.get(i), newDirtyRegion))
-				return;
-		}
-		// if new request is contains any existing requests,
-		// remove those
 		for (Iterator it = dirtyRegionQueue.iterator(); it.hasNext();) {
-			if (contains(newDirtyRegion, (DirtyRegion) it.next()))
+			// go through list of existing dirty regions and check if any
+			// dirty regions need to be discarded
+			DirtyRegion currentExisting = (DirtyRegion) it.next();
+			DirtyRegion outer = getOuterRegion(currentExisting, newDirtyRegion);
+			// if we already have a request which contains the new request,
+			// discard the new request
+			if (outer == currentExisting)
+				return;
+			// if new request contains any existing requests,
+			// remove those
+			if (outer == newDirtyRegion)
 				it.remove();
 		}
 		dirtyRegionQueue.add(newDirtyRegion);
@@ -273,14 +275,39 @@
 	}
 
 	/**
+	 * @deprecated use getOuterRegion() instead
+	 */
+	protected boolean contains(DirtyRegion root, DirtyRegion possible) {
+		// remove method post wtp 1.5.1
+		return isContained(root, possible);
+	}
+
+	/**
+	 * Used to determine if one dirty region contains the other and if so,
+	 * which is the one that contains it.
+	 * 
+	 * @param root
+	 * @param possible
+	 * @return the outer dirty region if it contains the other dirty region,
+	 *         null otherwise
+	 */
+	protected DirtyRegion getOuterRegion(DirtyRegion root, DirtyRegion possible) {
+		DirtyRegion outer = null;
+		if (isContained(root, possible))
+			outer = root;
+		else if (isContained(possible, root))
+			outer = possible;
+		return outer;
+	}
+
+	/**
 	 * Used to determine of a "possible" dirty region can be discarded in
 	 * favor of using just the "root" dirty region.
 	 * 
 	 * @return if the root dirty region contains possible, return true,
 	 *         otherwise return false
 	 */
-	protected boolean contains(DirtyRegion root, DirtyRegion possible) {
-
+	private boolean isContained(DirtyRegion root, DirtyRegion possible) {
 		int rootStart = root.getOffset();
 		int rootEnd = rootStart + root.getLength();
 		int possStart = possible.getOffset();
diff --git a/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/reconcile/StructuredRegionProcessor.java b/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/reconcile/StructuredRegionProcessor.java
index b93bf19..220127b 100644
--- a/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/reconcile/StructuredRegionProcessor.java
+++ b/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/reconcile/StructuredRegionProcessor.java
@@ -87,43 +87,149 @@
 	private IModelLifecycleListener fLifeCycleListener = new ModelLifecycleListener();
 
 	/**
-	 * @see org.eclipse.wst.sse.ui.internal.reconcile.DirtyRegionProcessor#contains(org.eclipse.jface.text.reconciler.DirtyRegion,
-	 *      org.eclipse.jface.text.reconciler.DirtyRegion)
+	 * @deprecated use getOuterRegion() instead
 	 */
 	protected boolean contains(DirtyRegion root, DirtyRegion possible) {
+		// remove method post wtp 1.5.1
 		// this method is a performance hit
 		// look for alternatives
 
-		boolean contains = false;
-		IStructuredModel sModel = getStructuredModelForRead(getDocument());
-		try {
-			if (sModel != null) {
-				IndexedRegion rootRegion = sModel.getIndexedRegion(root.getOffset());
-				IndexedRegion rootRegion2 = sModel.getIndexedRegion(root.getOffset() + root.getLength());
-				IndexedRegion possRegion = sModel.getIndexedRegion(possible.getOffset());
-				IndexedRegion possRegion2 = sModel.getIndexedRegion(possible.getOffset() + possible.getLength());
-				if (rootRegion != null && possRegion != null) {
-					int rootStart = rootRegion.getStartOffset();
-					int rootEnd = rootRegion2 != null ? rootRegion2.getEndOffset() : getDocument().getLength();
-					int possStart = possRegion.getStartOffset();
-					int possEnd = possRegion2 != null ? possRegion2.getEndOffset() : getDocument().getLength();
+		// call super to just check if possible is already contained within
+		// root based on offsets
+		boolean contains = super.contains(root, possible);
+		if (!contains) {
+			IStructuredModel sModel = getStructuredModelForRead(getDocument());
+			try {
+				if (sModel != null) {
+					// first just check if possregion appears after rootregion
+					IndexedRegion rootRegion = sModel.getIndexedRegion(root.getOffset());
+					IndexedRegion possRegion = sModel.getIndexedRegion(possible.getOffset());
+					if (rootRegion != null && possRegion != null) {
+						int rootStart = rootRegion.getStartOffset();
+						int possStart = possRegion.getStartOffset();
+						if (rootStart <= possStart) {
+							// then check if rootregion's end appears after
+							// possregion's end
+							IndexedRegion rootRegion2 = sModel.getIndexedRegion(root.getOffset() + root.getLength());
+							int rootEnd = rootRegion2 != null ? rootRegion2.getEndOffset() : getDocument().getLength();
+							IndexedRegion possRegion2 = sModel.getIndexedRegion(possible.getOffset() + possible.getLength());
+							int possEnd = possRegion2 != null ? possRegion2.getEndOffset() : getDocument().getLength();
 
-					if (rootStart <= possStart && rootEnd >= possEnd) {
-						contains = true;
+							if (rootEnd >= possEnd) {
+								contains = true;
+							}
+							if (DEBUG)
+								System.out.println("checking if [" + rootStart + ":" + rootEnd + "] contains [" + possStart + ":" + possEnd + "] ... " + contains); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+						}
 					}
-
-					if (DEBUG)
-						System.out.println("checking if [" + rootStart + ":" + rootEnd + "] contains [" + possStart + ":" + possEnd + "] ... " + contains); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
 				}
 			}
-		}
-		finally {
-			if (sModel != null)
-				sModel.releaseFromRead();
+			finally {
+				if (sModel != null)
+					sModel.releaseFromRead();
+			}
 		}
 		return contains;
 	}
 
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.wst.sse.ui.internal.reconcile.DirtyRegionProcessor#getOuterRegion(org.eclipse.jface.text.reconciler.DirtyRegion,
+	 *      org.eclipse.jface.text.reconciler.DirtyRegion)
+	 */
+	protected DirtyRegion getOuterRegion(DirtyRegion root, DirtyRegion possible) {
+		// first try simple region check if one region contains the other
+		DirtyRegion outer = super.getOuterRegion(root, possible);
+		if (outer == null) {
+			// now compare nodes
+			IStructuredModel sModel = getStructuredModelForRead(getDocument());
+			try {
+				if (sModel != null) {
+					IndexedRegion rootRegion = sModel.getIndexedRegion(root.getOffset());
+					IndexedRegion possRegion = sModel.getIndexedRegion(possible.getOffset());
+					if (rootRegion != null && possRegion != null) {
+						int rootStart = rootRegion.getStartOffset();
+						int possStart = possRegion.getStartOffset();
+						// first just check if rootregion starts before
+						// possregion
+						if (rootStart <= possStart) {
+							// check if possregion is inside rootregion
+							outer = _getOuterRegion(root, possible, sModel, rootStart, possStart);
+						}
+						else {
+							// otherwise if rootregion is inside possregion
+							outer = _getOuterRegion(possible, root, sModel, possStart, rootStart);
+						}
+					}
+				}
+			}
+			finally {
+				if (sModel != null)
+					sModel.releaseFromRead();
+			}
+		}
+		return outer;
+	}
+
+	/**
+	 * Assumes that when this method is called, region1's node start offset >=
+	 * region2's node start offset. Determines if region1 contains region2 or
+	 * vice versa. Returns region1 if:
+	 * <ul>
+	 * <li>region1's node region == region2's node region</li>
+	 * <li>region1's node region contains region2's node region</li>
+	 * </ul>
+	 * Returns region2 if:
+	 * <ul>
+	 * <li>region1's node region and region2's node region starts at same
+	 * offset but region2's node region is longer</li>
+	 * </ul>
+	 * Returns null otherwise.
+	 * 
+	 * @param region1
+	 * @param region2
+	 * @param sModel
+	 * @param region1NodeStart
+	 * @param region2NodeStart
+	 * @return outer dirty region or null if none exists.
+	 */
+	private DirtyRegion _getOuterRegion(DirtyRegion region1, DirtyRegion region2, IStructuredModel sModel, int region1NodeStart, int region2NodeStart) {
+		DirtyRegion outer = null;
+		int region1NodeEnd = -1;
+		int region2NodeEnd = -1;
+		// then check if region1's end appears after
+		// region2's end
+		IndexedRegion region1EndNode = sModel.getIndexedRegion(region1.getOffset() + region1.getLength());
+		if (region1EndNode == null) {
+			// if no end, just assume region spans all the
+			// way to the end so it includes other region
+			outer = region1;
+		}
+		else {
+			region1NodeEnd = region1EndNode.getEndOffset();
+			IndexedRegion region2EndNode = sModel.getIndexedRegion(region2.getOffset() + region2.getLength());
+			region2NodeEnd = region2EndNode != null ? region2EndNode.getEndOffset() : getDocument().getLength();
+			if (region1NodeEnd >= region2NodeEnd) {
+				// root contains or is equal to possible
+				outer = region1;
+			}
+			else if (region1NodeStart == region2NodeStart && region2NodeEnd >= region1NodeEnd) {
+				// possible contains root because they
+				// both start at same place but possible
+				// is longer
+				outer = region2;
+			}
+		}
+		if (DEBUG) {
+			if (outer != null)
+				System.out.println("checking if [" + region1NodeStart + ":" + region1NodeEnd + "] contains [" + region2NodeStart + ":" + region2NodeEnd + "] ... " + outer.toString()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+			else
+				System.out.println("checking if [" + region1NodeStart + ":" + region1NodeEnd + "] contains [" + region2NodeStart + ":" + region2NodeEnd + "] ... NO CONTAIN"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+		}
+		return outer;
+	}
+
 	/**
 	 * We already know content type from when we created the model, so just
 	 * use that.