blob: dccea5c037aabc666a4ecf1662526cad5490f02d [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include <vector>
#include "base/macros.h"
#include "base/strings/string_piece.h"
namespace content {
// Frame helper that manages the details of generating a quasi-stable unique
// name for the frame. The name is unique within a page, and is used for:
// - matching up session history items with recreated frames
// - layout test results
// Description of the current unique name format
// ---------------------------------------------
// Changing the format of unique name has a high cost, because it breaks
// backwards compatibility of session history (which stores unique names
// generated in the past on user's disk). The evolution of unique name in a
// mostly backwards-compatible way has resulted in the rather baroque format...
// uniqueName ::= <nullForMainFrame> | <assignedName> | <generatedName>
// Note: generatedName is used if assignedName is non-unique / conflicts with
// other frame's unique name.
// assignedName ::= value of iframe's name attribute
// or value assigned to
// Note: The name must be assigned *before* the first real commit: afterwards,
// the unique name is immutable.
// generatedName ::= oldGeneratedName newUniqueSuffix?
// Note: newUniqueSuffix is only present if oldGeneratedName is not unique.
// oldGeneratedName ::= "<!--framePath //" ancestorChain
// "/<!--frame" childCount "-->-->"
// Note: oldGeneratedName is generated by the internal GenerateCandidate()
// method.
// childCount ::= current number of siblings
// ancestorChain ::= concatenated unique names of ancestor chain,
// terminated on the first ancestor (if any) starting with
// "<!--framePath"; each ancestor's unique name is
// separated by "/" character
// Note: Two examples are provided below, with each portion of the name from a
// distinct ancestor annotated.
// Example ancestor chain #1:
// "grandparent/parent"
// | #1 | #2 |
// Example ancestor chain #2:
// "<!--framePath //foo/bar/<!--frame42-->-->/blah/foobar"
// | #1 | #2 | #3 |
// newUniqueSuffix ::= "<!--framePosition" framePosition "/" retryNumber "-->"
// framePosition ::= "-" numberOfSiblingsBeforeChild
// [ framePosition-forParent? ]
// retryNumber ::= smallest non-negative integer resulting in unique name
class UniqueNameHelper {
// Adapter class so UniqueNameHelper can be used with both RenderFrameImpl and
// ExplodedFrameState.
class FrameAdapter {
FrameAdapter() {}
virtual ~FrameAdapter();
virtual bool IsMainFrame() const = 0;
virtual bool IsCandidateUnique(const std::string& name) const = 0;
// Returns the number of sibling frames of this frame. Note this should not
// include this frame in the count.
virtual int GetSiblingCount() const = 0;
virtual int GetChildCount() const = 0;
// Sets the reference point for iterations that walk up the frame tree.
enum class BeginPoint {
// This should be the default: it indicates the logical iteration
// operation began on this frame and the walking logic should retrieve the
// parent frame as normal.
// For implementing the pending child frame adapter, which delegates to
// its future parent's FrameAdapter. Walking up the tree should not skip
// this frame; instead it should treat this frame as the parent, since the
// logical iteration began with a pending child frame.
// Returns a vector of the strings representing the name of each frame in
// the chain from this frame to the root frame. |begin_point| indicates the
// reference point for starting the collection. |should_stop| is a
// boolean predicate that indicates when to stop collection of names.
virtual std::vector<base::StringPiece> CollectAncestorNames(
BeginPoint begin_point,
bool (*should_stop)(base::StringPiece)) const = 0;
// Returns a vector of ints representing the child index of each frame in
// the chain from this frame to the root.
virtual std::vector<int> GetFramePosition(BeginPoint begin_point) const = 0;
explicit UniqueNameHelper(FrameAdapter* frame);
// Returns the generated unique name.
const std::string& value() const { return unique_name_; }
// Used to propagate an already calculated unique name.
// TODO(lukasza): It would be nice to assert uniqueness of the propagated
// name here but:
// 1) uniqueness is currently violated by provisional/old frame pairs.
// 2) there is an unresolved race between 2 OOPIFs, that can result in a
// non-unique unique name: see
void set_propagated_name(const std::string& name) { unique_name_ = name; }
// Note: when creating a new child frame, the unique name needs to be
// calculated before the child frame is created. To avoid this chicken and
// egg problem, this method is designed to be called on the *parent* frame of
// the future new child frame and return the value the new child frame should
// use.
std::string GenerateNameForNewChildFrame(const std::string& name) const;
// Called after a browsing context name change to generate a new name. Note
// that this should not be called if the frame is no longer displaying the
// initial empty document, as unique name changes after that point will break
// history navigations. See
void UpdateName(const std::string& name);
FrameAdapter* const frame_;
std::string unique_name_;
} // namespace content