Index: Filter.java
===================================================================
--- Filter.java	(revision 406129)
+++ Filter.java	(working copy)
@@ -1,7 +1,7 @@
 package org.apache.lucene.search;
 
 /**
- * Copyright 2004 The Apache Software Foundation
+ * Copyright 2006 The Apache Software Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,11 +19,30 @@
 import java.util.BitSet;
 import java.io.IOException;
 import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.util.DocNrSkipper;
 
 /** Abstract base class providing a mechanism to restrict searches to a subset
  of an index. */
-public abstract class Filter implements java.io.Serializable {
+public abstract class Filter implements java.io.Serializable, SkipFilter {
   /** Returns a BitSet with true for documents which should be permitted in
     search results, and false for those that should not. */
   public abstract BitSet bits(IndexReader reader) throws IOException;
+  
+  /** Returns a DocNrSkipper that provides the documents which should be
+   *  permitted in search results.
+   *
+   *  @return <code>null</code>. Subclasses can provide their own implementation.
+   */
+  public DocNrSkipper getDocNrSkipper(IndexReader reader) throws IOException {
+    return null;
+/* For testing only:
+    final IndexReader r = reader;
+    return new DocNrSkipper() {
+      private BitSet bitset = bits(r);
+      public int nextDocNr(int docNr) {
+        return bitset.nextSetBit(docNr);
+      }
+    };
+ */
+  }
 }
Index: IndexSearcher.java
===================================================================
--- IndexSearcher.java	(revision 406129)
+++ IndexSearcher.java	(working copy)
@@ -23,15 +23,21 @@
 import org.apache.lucene.document.Document;
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.Term;
+import org.apache.lucene.util.DocNrSkipper;
 
 /** Implements search over a single IndexReader.
  *
  * <p>Applications usually need only call the inherited {@link #search(Query)}
  * or {@link #search(Query,Filter)} methods. For performance reasons it is 
  * recommended to open only one IndexSearcher and use it for all of your searches.
- * 
+ * <br>When a Filter returns non null for
+ * {@link Filter.getDocNrSkipper(IndexReader)}, this DocNrSkipper is used
+ * instead of the result of the {@link Filter.#bits(IndexReader)}
+ * method, and the Scorer of the searched query should implement skipTo().
+ *
  * <p>Note that you can only access Hits from an IndexSearcher as long as it is
  * not yet closed, otherwise an IOException will be thrown. 
+ *
  */
 public class IndexSearcher extends Searcher {
   IndexReader reader;
@@ -114,22 +120,38 @@
   // inherit javadoc
   public void search(Weight weight, Filter filter,
                      final HitCollector results) throws IOException {
-    HitCollector collector = results;
-    if (filter != null) {
+    Scorer scorer = weight.scorer(reader);
+    if (scorer == null)
+      return;
+
+    if (filter == null) {
+      scorer.score(results);
+      return;
+    }
+
+    DocNrSkipper skipper = filter.getDocNrSkipper(reader);
+    if (skipper != null) { // skipper for filtering, skipTo() used on scorer:
+      int docNr = skipper.nextDocNr(0);
+      while ((docNr != -1) && scorer.skipTo(docNr)) {
+        int scorerDocNr = scorer.doc();
+        if (scorerDocNr != docNr) {
+          docNr = skipper.nextDocNr(scorerDocNr);
+        } else {
+          results.collect(docNr, scorer.score());
+          docNr = skipper.nextDocNr(docNr + 1);
+        }
+      }
+    } else { // bits for filtering, skipTo() not used on scorer:
       final BitSet bits = filter.bits(reader);
-      collector = new HitCollector() {
-          public final void collect(int doc, float score) {
-            if (bits.get(doc)) {                  // skip docs not in bits
-              results.collect(doc, score);
-            }
+      HitCollector collector = new HitCollector() {
+        public final void collect(int doc, float score) {
+          if (bits.get(doc)) {                  // skip docs not in bits
+            results.collect(doc, score);
           }
-        };
+        }
+      };
+      scorer.score(collector);
     }
-
-    Scorer scorer = weight.scorer(reader);
-    if (scorer == null)
-      return;
-    scorer.score(collector);
   }
 
   public Query rewrite(Query original) throws IOException {
